From d260f9eb9f69d614cd05184608a77312ce70ac7b Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:53:57 -0700 Subject: [PATCH 001/276] Modify the adding sample data part for timeline (#6919) (#6934) (cherry picked from commit 48144c82f44cfda7f118e8f87b6d3dc1be01ec5a) Signed-off-by: Yuanqi(Ella) Zhu Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- src/core/server/index.ts | 2 + src/core/server/saved_objects/import/index.ts | 7 +++- .../server/saved_objects/import/utils.test.ts | 33 ++++++++++++++++ src/core/server/saved_objects/import/utils.ts | 39 +++++++++++++++++-- .../sample_data/data_sets/util.test.ts | 32 +++++++++++++++ .../services/sample_data/data_sets/util.ts | 17 ++++++++ 6 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/core/server/index.ts b/src/core/server/index.ts index 5e2655bfa164..731addad2e4a 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -328,6 +328,8 @@ export { Permissions, updateDataSourceNameInVegaSpec, extractVegaSpecFromSavedObject, + extractTimelineExpression, + updateDataSourceNameInTimeline, } from './saved_objects'; export { diff --git a/src/core/server/saved_objects/import/index.ts b/src/core/server/saved_objects/import/index.ts index f265f714cac9..c6852940959c 100644 --- a/src/core/server/saved_objects/import/index.ts +++ b/src/core/server/saved_objects/import/index.ts @@ -43,4 +43,9 @@ export { SavedObjectsResolveImportErrorsOptions, SavedObjectsImportRetry, } from './types'; -export { updateDataSourceNameInVegaSpec, extractVegaSpecFromSavedObject } from './utils'; +export { + updateDataSourceNameInVegaSpec, + extractVegaSpecFromSavedObject, + extractTimelineExpression, + updateDataSourceNameInTimeline, +} from './utils'; diff --git a/src/core/server/saved_objects/import/utils.test.ts b/src/core/server/saved_objects/import/utils.test.ts index 36dd427377a9..0203a574c049 100644 --- a/src/core/server/saved_objects/import/utils.test.ts +++ b/src/core/server/saved_objects/import/utils.test.ts @@ -9,6 +9,7 @@ import { getDataSourceTitleFromId, getUpdatedTSVBVisState, updateDataSourceNameInVegaSpec, + updateDataSourceNameInTimeline, } from './utils'; import { parse } from 'hjson'; import { isEqual } from 'lodash'; @@ -199,6 +200,38 @@ describe('updateDataSourceNameInVegaSpec()', () => { }); }); +describe('updateDataSourceNameInTimeline()', () => { + test('When a timeline expression does not contain a data source name, modify the expression', () => { + const expression = + '.opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp).lines(show=true).points(show=true).yaxis(label="Average bytes")'; + const expectedExpression = + '.opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name="newDataSource").lines(show=true).points(show=true).yaxis(label="Average bytes")'; + expect(updateDataSourceNameInTimeline(expression, 'newDataSource')).toBe(expectedExpression); + }); + + test('When a timeline expression contains a data source name, then do nothing', () => { + const expression = + '.opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name=newDataSource).lines(show=true).points(show=true).yaxis(label="Average bytes")'; + expect(updateDataSourceNameInTimeline(expression, 'newDataSource')).toBe(expression); + }); + + test('When a timeline expression contains multiple timeline expression, modify each of them', () => { + const expression = + '.opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp,data_source_name=aos211).lines(show=true).points(show=true).yaxis(label="Average bytes"),.opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp).lines(show=true).points(show=true).yaxis(label="Average bytes")'; + const expectedExpression = + '.opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp,data_source_name=aos211).lines(show=true).points(show=true).yaxis(label="Average bytes"),.opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name="aos211").lines(show=true).points(show=true).yaxis(label="Average bytes")'; + expect(updateDataSourceNameInTimeline(expression, 'aos211')).toBe(expectedExpression); + }); + + test('When a timeline expression contains multiple timeline expression and the datasource name contains space, we modify each of them', () => { + const expression = + '.es(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp).lines(show=true).points(show=true).yaxis(label="Average bytes"),.elasticsearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp).lines(show=true).points(show=true).yaxis(label="Average bytes")'; + const expectedExpression = + '.es(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name="aos 211").lines(show=true).points(show=true).yaxis(label="Average bytes"),.elasticsearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name="aos 211").lines(show=true).points(show=true).yaxis(label="Average bytes")'; + expect(updateDataSourceNameInTimeline(expression, 'aos 211')).toBe(expectedExpression); + }); +}); + describe('extractVegaSpecFromSavedObject()', () => { test('For a Vega visualization saved object, return its spec', () => { const spec = 'some-vega-spec'; diff --git a/src/core/server/saved_objects/import/utils.ts b/src/core/server/saved_objects/import/utils.ts index 92835ec017b3..367824b8db41 100644 --- a/src/core/server/saved_objects/import/utils.ts +++ b/src/core/server/saved_objects/import/utils.ts @@ -91,6 +91,25 @@ export const updateDataSourceNameInVegaSpec = ( }); }; +export const updateDataSourceNameInTimeline = ( + timelineExpression: string, + dataSourceTitle: string +) => { + const expressionRegex = /\.(opensearch|es|elasticsearch)\(([^)]*)\)/g; + + const replaceCallback = (match: string, funcName: string, args: string) => { + if (!args.includes('data_source_name')) { + let expressionArgs = args.trim(); + expressionArgs = `${expressionArgs}, data_source_name="${dataSourceTitle}"`; + return `.${funcName}(${expressionArgs})`; + } + return match; + }; + + const modifiedExpression = timelineExpression.replace(expressionRegex, replaceCallback); + return modifiedExpression; +}; + export const getDataSourceTitleFromId = async ( dataSourceId: string, savedObjectsClient: SavedObjectsClientContract @@ -102,7 +121,7 @@ export const getDataSourceTitleFromId = async ( }; export const extractVegaSpecFromSavedObject = (savedObject: SavedObject) => { - if (isVegaVisualization(savedObject)) { + if (confirmVisualizationType(savedObject, 'vega')) { // @ts-expect-error const visStateObject = JSON.parse(savedObject.attributes?.visState); return visStateObject.params.spec; @@ -111,12 +130,26 @@ export const extractVegaSpecFromSavedObject = (savedObject: SavedObject) => { return undefined; }; -const isVegaVisualization = (savedObject: SavedObject) => { +export const extractTimelineExpression = (savedObject: SavedObject) => { + if (!confirmVisualizationType(savedObject, 'timelion')) { + return undefined; + } + // @ts-expect-error + const visStateString = savedObject.attributes?.visState; + if (!visStateString) { + return undefined; + } + + const visStateObject = JSON.parse(visStateString); + return visStateObject.params.expression; +}; + +const confirmVisualizationType = (savedObject: SavedObject, visualizationType: string) => { // @ts-expect-error const visState = savedObject.attributes?.visState; if (!!visState) { const visStateObject = JSON.parse(visState); - return !!visStateObject.type && visStateObject.type === 'vega'; + return !!visStateObject.type && visStateObject.type === visualizationType; } return false; }; diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.test.ts b/src/plugins/home/server/services/sample_data/data_sets/util.test.ts index 6a7e7814761f..1b02fa778f98 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/util.test.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/util.test.ts @@ -63,6 +63,38 @@ describe('getSavedObjectsWithDataSource()', () => { expect(updatedVegaVisualizationsFields).toEqual(expect.arrayContaining(expectedUpdatedFields)); }); + it('should processing timeline saved object and add datasource name in the end', () => { + const dataSourceId = 'some-datasource-id'; + const dataSourceName = 'dataSourceName'; + const savedObjects = [ + { + id: 'saved-object-1', + type: 'visualization', + title: 'example', + attributes: { + title: 'example', + visState: + '{"title":"(Timeline) Avg bytes over time","type":"timelion","aggs":[],"params":{"expression":".opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp).lines(show=true).points(show=true).yaxis(label=\\"Average bytes\\")","interval":"auto"}}', + }, + references: [], + }, + ]; + + expect(getSavedObjectsWithDataSource(savedObjects, dataSourceId, dataSourceName)).toEqual([ + { + id: 'some-datasource-id_saved-object-1', + type: 'visualization', + title: 'example', + attributes: { + title: 'example_dataSourceName', + visState: + '{"title":"(Timeline) Avg bytes over time","type":"timelion","aggs":[],"params":{"expression":".opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name=\\"dataSourceName\\").lines(show=true).points(show=true).yaxis(label=\\"Average bytes\\")","interval":"auto"}}', + }, + references: [], + }, + ]); + }); + it('should update index-pattern id and references with given data source', () => { const dataSourceId = 'some-datasource-id'; const dataSourceName = 'Data Source Name'; diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.ts b/src/plugins/home/server/services/sample_data/data_sets/util.ts index 04eff6036e88..5585720649dd 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/util.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/util.ts @@ -6,7 +6,9 @@ import { SavedObject } from 'opensearch-dashboards/server'; import { extractVegaSpecFromSavedObject, + extractTimelineExpression, updateDataSourceNameInVegaSpec, + updateDataSourceNameInTimeline, } from '../../../../../../core/server'; import { SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; @@ -114,6 +116,21 @@ export const getSavedObjectsWithDataSource = ( name: 'dataSource', }); } + + const timelineExpression = extractTimelineExpression(saveObject); + if (!!timelineExpression) { + // Get the timeline expression with the updated data source name + const modifiedExpression = updateDataSourceNameInTimeline( + timelineExpression, + dataSourceTitle + ); + + // @ts-expect-error + const timelineStateObject = JSON.parse(saveObject.attributes?.visState); + timelineStateObject.params.expression = modifiedExpression; + // @ts-expect-error + saveObject.attributes.visState = JSON.stringify(timelineStateObject); + } } } From 7ee7a75b046eb3da124f091f913346ca9f570c9e Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:53:26 -0700 Subject: [PATCH 002/276] Add release notes for 1.3.17 (#6935) (#6939) (cherry picked from commit cb84bfb1ffc21ecfe379a3230f9186563927faaa) Signed-off-by: Divya Madala Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- ...pensearch-dashboards.release-notes-1.3.17.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 release-notes/opensearch-dashboards.release-notes-1.3.17.md diff --git a/release-notes/opensearch-dashboards.release-notes-1.3.17.md b/release-notes/opensearch-dashboards.release-notes-1.3.17.md new file mode 100644 index 000000000000..e3f160692e0b --- /dev/null +++ b/release-notes/opensearch-dashboards.release-notes-1.3.17.md @@ -0,0 +1,17 @@ +# Version 1.3.17 Release Notes + +### 🛡 Security + +### 📈 Features/Enhancements + +### 🐛 Bug Fixes + +- Replace control characters before logging ([#6590](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6590)) + +### 🚞 Infrastructure + +### 📝 Documentation + +### 🛠 Maintenance + +- [Version] Increment version to 1.3.17 ([#6845](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6845)) \ No newline at end of file From ad4790924efe1ad34ed1b36f953b25ee4c554985 Mon Sep 17 00:00:00 2001 From: Yu Jin <112784385+yujin-emma@users.noreply.github.com> Date: Wed, 5 Jun 2024 23:35:38 -0700 Subject: [PATCH 003/276] [Manual Backport 2.x] [Multiple DataSource] Do not support import data source object to Local cluster when not enable data source (#6913) * [Backport #6395] Do not support import data source object to Local cluster when not enable data source Signed-off-by: yujin-emma * Update CHANGELOG.md Signed-off-by: yujin-emma * fix: integration test failure Signed-off-by: SuZhou-Joe Signed-off-by: yujin-emma --------- Signed-off-by: yujin-emma Signed-off-by: SuZhou-Joe Co-authored-by: SuZhou-Joe --- CHANGELOG.md | 1 + .../import/import_saved_objects.test.ts | 105 +++++++++++++++++- .../import/import_saved_objects.ts | 25 +++++ src/core/server/saved_objects/import/types.ts | 2 +- .../import/validate_object_id.test.ts | 59 ++++++++++ .../import/validate_object_id.ts | 40 +++++++ .../server/saved_objects/routes/import.ts | 4 + .../public/lib/import_file.ts | 6 +- .../objects_table/components/flyout.test.tsx | 1 + .../objects_table/components/flyout.tsx | 10 +- ...apper_for_check_workspace_conflict.test.ts | 2 +- 11 files changed, 248 insertions(+), 7 deletions(-) create mode 100644 src/core/server/saved_objects/import/validate_object_id.test.ts create mode 100644 src/core/server/saved_objects/import/validate_object_id.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eb066f49315..5f7d089ba687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### 📈 Features/Enhancements - [Multiple Datasource] Add TLS configuration for multiple data sources ([#6171](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6171)) +- [Multiple DataSource] Do not support import data source object to Local cluster when not enable data source ([#6395](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6395)) ### 🐛 Bug Fixes diff --git a/src/core/server/saved_objects/import/import_saved_objects.test.ts b/src/core/server/saved_objects/import/import_saved_objects.test.ts index fff5b60c89cc..ea4ac66b1a0b 100644 --- a/src/core/server/saved_objects/import/import_saved_objects.test.ts +++ b/src/core/server/saved_objects/import/import_saved_objects.test.ts @@ -96,11 +96,12 @@ describe('#importSavedObjectsFromStream', () => { let savedObjectsClient: jest.Mocked; let typeRegistry: jest.Mocked; const namespace = 'some-namespace'; - const testDataSourceId = 'some-datasource'; + const testDataSourceId = uuidv4(); const setupOptions = ( createNewCopies: boolean = false, - dataSourceId: string | undefined = undefined + dataSourceId: string | undefined = undefined, + dataSourceEnabled: boolean | undefined = false ): SavedObjectsImportOptions => { readStream = new Readable(); savedObjectsClient = savedObjectsClientMock.create(); @@ -135,6 +136,17 @@ describe('#importSavedObjectsFromStream', () => { attributes: { title: 'some-title' }, }; }; + + const createDataSourceObject = (): SavedObject<{ + title: string; + }> => { + return { + type: 'data-source', + id: uuidv4(), + references: [], + attributes: { title: 'some-title' }, + }; + }; const createError = (): SavedObjectsImportError => { const title = 'some-title'; return { @@ -589,5 +601,94 @@ describe('#importSavedObjectsFromStream', () => { const expectedErrors = errors.map(({ type, id }) => expect.objectContaining({ type, id })); expect(result).toEqual({ success: false, successCount: 0, errors: expectedErrors }); }); + + test('early return if import data source objects to non-MDS cluster', async () => { + const options = setupOptions(false, testDataSourceId, false); + const dsObj = createDataSourceObject(); + const dsExportedObj = createObject(testDataSourceId); + const collectedObjects = [dsObj, dsExportedObj]; + + const errors = [ + { + type: dsObj.type, + id: dsObj.id, + title: dsObj.attributes.title, + meta: { title: dsObj.attributes.title }, + error: { type: 'unsupported_type' }, + }, + { + type: dsExportedObj.type, + id: dsExportedObj.id, + title: dsExportedObj.attributes.title, + meta: { title: dsExportedObj.attributes.title }, + error: { type: 'unsupported_type' }, + }, + ]; + getMockFn(collectSavedObjects).mockResolvedValue({ + errors: [], + collectedObjects, + importIdMap: new Map(), + }); + const result = await importSavedObjectsFromStream(options); + const expectedErrors = errors.map(({ type, id }) => expect.objectContaining({ type, id })); + expect(result).toEqual({ success: false, successCount: 0, errors: expectedErrors }); + }); + + test('early return if import mixed non/data source objects to non-MDS cluster', async () => { + const options = setupOptions(false, testDataSourceId, false); + const dsObj = createDataSourceObject(); + const dsExportedObj = createObject(testDataSourceId); + const nonDsExportedObj = createObject(); + const collectedObjects = [dsObj, dsExportedObj, nonDsExportedObj]; + + const errors = [ + { + type: dsObj.type, + id: dsObj.id, + title: dsObj.attributes.title, + meta: { title: dsObj.attributes.title }, + error: { type: 'unsupported_type' }, + }, + { + type: dsExportedObj.type, + id: dsExportedObj.id, + title: dsExportedObj.attributes.title, + meta: { title: dsExportedObj.attributes.title }, + error: { type: 'unsupported_type' }, + }, + ]; + getMockFn(collectSavedObjects).mockResolvedValue({ + errors: [], + collectedObjects, + importIdMap: new Map(), + }); + const result = await importSavedObjectsFromStream(options); + const expectedErrors = errors.map(({ type, id }) => expect.objectContaining({ type, id })); + expect(result).toEqual({ success: false, successCount: 0, errors: expectedErrors }); + }); + + test('early return if import single data source objects to non-MDS cluster', async () => { + const options = setupOptions(false, testDataSourceId, false); + const dsObj = createDataSourceObject(); + const collectedObjects = [dsObj]; + + const errors = [ + { + type: dsObj.type, + id: dsObj.id, + title: dsObj.attributes.title, + meta: { title: dsObj.attributes.title }, + error: { type: 'unsupported_type' }, + }, + ]; + getMockFn(collectSavedObjects).mockResolvedValue({ + errors: [], + collectedObjects, + importIdMap: new Map(), + }); + const result = await importSavedObjectsFromStream(options); + const expectedErrors = errors.map(({ type, id }) => expect.objectContaining({ type, id })); + expect(result).toEqual({ success: false, successCount: 0, errors: expectedErrors }); + }); }); }); diff --git a/src/core/server/saved_objects/import/import_saved_objects.ts b/src/core/server/saved_objects/import/import_saved_objects.ts index e82b4e634e0f..cfd091149004 100644 --- a/src/core/server/saved_objects/import/import_saved_objects.ts +++ b/src/core/server/saved_objects/import/import_saved_objects.ts @@ -33,6 +33,7 @@ import { SavedObjectsImportError, SavedObjectsImportResponse, SavedObjectsImportOptions, + SavedObjectsImportUnsupportedTypeError, } from './types'; import { validateReferences } from './validate_references'; import { checkOriginConflicts } from './check_origin_conflicts'; @@ -40,6 +41,7 @@ import { createSavedObjects } from './create_saved_objects'; import { checkConflicts } from './check_conflicts'; import { regenerateIds } from './regenerate_ids'; import { checkConflictsForDataSource } from './check_conflict_for_data_source'; +import { isSavedObjectWithDataSource } from './validate_object_id'; /** * Import saved objects from given stream. See the {@link SavedObjectsImportOptions | options} for more @@ -58,6 +60,7 @@ export async function importSavedObjectsFromStream({ dataSourceId, dataSourceTitle, workspaces, + dataSourceEnabled, }: SavedObjectsImportOptions): Promise { let errorAccumulator: SavedObjectsImportError[] = []; const supportedTypes = typeRegistry.getImportableAndExportableTypes().map((type) => type.name); @@ -69,6 +72,28 @@ export async function importSavedObjectsFromStream({ supportedTypes, dataSourceId, }); + // if not enable data_source, throw error early + if (!dataSourceEnabled) { + const notSupportedErrors: SavedObjectsImportError[] = collectSavedObjectsResult.collectedObjects.reduce( + (errors: SavedObjectsImportError[], obj) => { + if (obj.type === 'data-source' || isSavedObjectWithDataSource(obj.id)) { + const error: SavedObjectsImportUnsupportedTypeError = { type: 'unsupported_type' }; + const { title } = obj.attributes; + errors.push({ error, type: obj.type, id: obj.id, title, meta: { title } }); + } + return errors; // Return the accumulator in each iteration + }, + [] + ); + if (notSupportedErrors?.length > 0) { + return { + successCount: 0, + success: false, + errors: notSupportedErrors, + }; + } + } + errorAccumulator = [...errorAccumulator, ...collectSavedObjectsResult.errors]; /** Map of all IDs for objects that we are attempting to import; each value is empty by default */ let importIdMap = collectSavedObjectsResult.importIdMap; diff --git a/src/core/server/saved_objects/import/types.ts b/src/core/server/saved_objects/import/types.ts index 426d4cfde86c..8612870fcf56 100644 --- a/src/core/server/saved_objects/import/types.ts +++ b/src/core/server/saved_objects/import/types.ts @@ -189,7 +189,7 @@ export interface SavedObjectsImportOptions { createNewCopies: boolean; dataSourceId?: string; dataSourceTitle?: string; - /** if specified, will import in given workspaces */ + dataSourceEnabled?: boolean; workspaces?: SavedObjectsBaseOptions['workspaces']; } diff --git a/src/core/server/saved_objects/import/validate_object_id.test.ts b/src/core/server/saved_objects/import/validate_object_id.test.ts new file mode 100644 index 000000000000..2f0cb3c6487a --- /dev/null +++ b/src/core/server/saved_objects/import/validate_object_id.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { isSavedObjectWithDataSource } from './validate_object_id'; + +describe('isObjectWithDataSource', () => { + test('should return false for valid object with data source ID but in wrong format', () => { + // Valid ID with two parts separated by underscore, and both parts being UUIDs + const inValidId = 'invalid_uuid_1234-invalid_uuid_5678'; + expect(isSavedObjectWithDataSource(inValidId)).toBe(false); + }); + + test('should return false for invalid IDs', () => { + // Missing underscore + const invalidId1 = 'missingunderscore'; + expect(isSavedObjectWithDataSource(invalidId1)).toBe(false); + + // Invalid UUID in the second part + const invalidId2 = 'valid_uuid_1234-invalid_uuid'; + expect(isSavedObjectWithDataSource(invalidId2)).toBe(false); + + // Missing second part + const invalidId3 = 'valid_uuid_1234'; + expect(isSavedObjectWithDataSource(invalidId3)).toBe(false); + + // More than two parts + const invalidId4 = 'valid_uuid_1234-valid_uuid_5678-extra_part'; + expect(isSavedObjectWithDataSource(invalidId4)).toBe(false); + }); + + test('should return false for non-UUID parts', () => { + // First part is not a UUID + const invalidId1 = 'not_a_uuid_valid_uuid_1234'; + expect(isSavedObjectWithDataSource(invalidId1)).toBe(false); + + // Second part is not a UUID + const invalidId2 = 'valid_uuid_1234_not_a_uuid'; + expect(isSavedObjectWithDataSource(invalidId2)).toBe(false); + + // Both parts are not UUIDs + const invalidId3 = 'not_a_uuid_not_a_uuid'; + expect(isSavedObjectWithDataSource(invalidId3)).toBe(false); + }); + + test('should return false for string with underscore but not with UUID', () => { + // First part is not a UUID + const invalidId = 'saved_object_with_index_pattern_conflict'; + expect(isSavedObjectWithDataSource(invalidId)).toBe(false); + }); + + test('should return false for string with underscore but with three UUIDs', () => { + // First part is not a UUID + const invalidId = + '7cbd2350-2223-11e8-b802-5bcf64c2cfb4_7cbd2350-2223-11e8-b802-5bcf64c2cfb4_7cbd2350-2223-11e8-b802-5bcf64c2cfb4'; + expect(isSavedObjectWithDataSource(invalidId)).toBe(false); + }); +}); diff --git a/src/core/server/saved_objects/import/validate_object_id.ts b/src/core/server/saved_objects/import/validate_object_id.ts new file mode 100644 index 000000000000..9a496c4d572a --- /dev/null +++ b/src/core/server/saved_objects/import/validate_object_id.ts @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * When enable multiple data source, exported objects from a data source will maintain object id like + * "69a34b00-9ee8-11e7-8711-e7a007dcef99_7cbd2350-2223-11e8-b802-5bcf64c2cfb4" + * two UUIDs are connected with a underscore, + * before the underscore, the UUID represents the data source + * after the underscore, the UUID is the original object id + * when disable multiple data source, the exported object from local cluster will look like 7cbd2350-2223-11e8-b802-5bcf64c2cfb4 + * we can use this format to tell out whether a single object is exported from MDS enabled/disabled cluster + * + * This file to going to group some validate function to tell source of object based on the object id + */ + +/** + * + * @param candidate: string without underscore + * @returns + */ +const isUUID = (candidate: string): boolean => { + // Regular expression pattern for UUID + const uuidPattern: RegExp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + return uuidPattern.test(candidate); +}; + +/** + * + * @param id single object id + * @returns + */ +export const isSavedObjectWithDataSource = (id: string): boolean => { + const idParts = id.split('_'); + /** + * check with the + */ + return idParts && idParts.length === 2 && idParts.every(isUUID); +}; diff --git a/src/core/server/saved_objects/routes/import.ts b/src/core/server/saved_objects/routes/import.ts index 1fc739ea168c..a2a5bdcacd7a 100644 --- a/src/core/server/saved_objects/routes/import.ts +++ b/src/core/server/saved_objects/routes/import.ts @@ -64,6 +64,7 @@ export const registerImportRoute = (router: IRouter, config: SavedObjectConfig) workspaces: schema.maybe( schema.oneOf([schema.string(), schema.arrayOf(schema.string())]) ), + dataSourceEnabled: schema.maybe(schema.boolean({ defaultValue: false })), }, { validate: (object) => { @@ -116,6 +117,8 @@ export const registerImportRoute = (router: IRouter, config: SavedObjectConfig) workspaces = [workspaces]; } + const dataSourceEnabled = req.query.dataSourceEnabled; + const result = await importSavedObjectsFromStream({ savedObjectsClient: context.core.savedObjects.client, typeRegistry: context.core.savedObjects.typeRegistry, @@ -126,6 +129,7 @@ export const registerImportRoute = (router: IRouter, config: SavedObjectConfig) dataSourceId, dataSourceTitle, workspaces, + dataSourceEnabled, }); return res.ok({ body: result }); diff --git a/src/plugins/saved_objects_management/public/lib/import_file.ts b/src/plugins/saved_objects_management/public/lib/import_file.ts index 3753a8251e10..f5156cd94f1d 100644 --- a/src/plugins/saved_objects_management/public/lib/import_file.ts +++ b/src/plugins/saved_objects_management/public/lib/import_file.ts @@ -41,7 +41,8 @@ export async function importFile( http: HttpStart, file: File, { createNewCopies, overwrite }: ImportMode, - selectedDataSourceId?: string + selectedDataSourceId?: string, + dataSourceEnabled?: boolean ) { const formData = new FormData(); formData.append('file', file); @@ -49,6 +50,9 @@ export async function importFile( if (selectedDataSourceId) { query.dataSourceId = selectedDataSourceId; } + if (dataSourceEnabled) { + query.dataSourceEnabled = dataSourceEnabled; + } return await http.post('/api/saved_objects/_import', { body: formData, headers: { diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx index 4237582ea53a..d68f17a64f6c 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx @@ -221,6 +221,7 @@ describe('Flyout', () => { createNewCopies: true, overwrite: true, }, + undefined, undefined ); expect(component.state()).toMatchObject({ diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx index b2542c4a56c0..fb2f98855364 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx @@ -195,13 +195,19 @@ export class Flyout extends Component { * Does the initial import of a file, resolveImportErrors then handles errors and retries */ import = async () => { - const { http } = this.props; + const { http, dataSourceEnabled } = this.props; const { file, importMode, selectedDataSourceId } = this.state; this.setState({ status: 'loading', error: undefined }); // Import the file try { - const response = await importFile(http, file!, importMode, selectedDataSourceId); + const response = await importFile( + http, + file!, + importMode, + selectedDataSourceId, + dataSourceEnabled + ); this.setState(processImportResponse(response), () => { // Resolve import errors right away if there's no index patterns to match // This will ask about overwriting each object, etc diff --git a/src/plugins/workspace/server/saved_objects/integration_tests/saved_objects_wrapper_for_check_workspace_conflict.test.ts b/src/plugins/workspace/server/saved_objects/integration_tests/saved_objects_wrapper_for_check_workspace_conflict.test.ts index 1700c51ee11e..7967992690d0 100644 --- a/src/plugins/workspace/server/saved_objects/integration_tests/saved_objects_wrapper_for_check_workspace_conflict.test.ts +++ b/src/plugins/workspace/server/saved_objects/integration_tests/saved_objects_wrapper_for_check_workspace_conflict.test.ts @@ -493,7 +493,7 @@ describe('saved_objects_wrapper_for_check_workspace_conflict integration test', const importWithWorkspacesResult = await osdTestServer.request .post( root, - `/api/saved_objects/_import?workspaces=${createdFooWorkspace.id}&overwrite=true` + `/api/saved_objects/_import?workspaces=${createdFooWorkspace.id}&overwrite=true&dataSourceEnabled=true` ) .attach( 'file', From 321e19010623d15bb631f341261fe1f31b17791b Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:59:11 +0800 Subject: [PATCH 004/276] [Multi DataSource] Add removedComponentIds for data source selection service (#6920) (#6944) * add removedComponentIds for data source selection service to fallback * update comment * update component variable snapshot in navigation plugin * Changeset file for PR #6920 created/updated --------- (cherry picked from commit efab1a8d56ddf8b311e238e97e4ac878b89bf686) Signed-off-by: tygao Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: Lu Yu --- changelogs/fragments/6920.yml | 2 ++ .../service/data_source_selection_service.test.ts | 12 ++++++++++++ .../public/service/data_source_selection_service.ts | 7 +++++++ .../__snapshots__/top_nav_menu.test.tsx.snap | 2 ++ 4 files changed, 23 insertions(+) create mode 100644 changelogs/fragments/6920.yml diff --git a/changelogs/fragments/6920.yml b/changelogs/fragments/6920.yml new file mode 100644 index 000000000000..f688be79b428 --- /dev/null +++ b/changelogs/fragments/6920.yml @@ -0,0 +1,2 @@ +feat: +- [Multi DataSource] Add removedComponentIds for data source selection service ([#6920](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6920)) \ No newline at end of file diff --git a/src/plugins/data_source_management/public/service/data_source_selection_service.test.ts b/src/plugins/data_source_management/public/service/data_source_selection_service.test.ts index 65957379517f..116677704e5f 100644 --- a/src/plugins/data_source_management/public/service/data_source_selection_service.test.ts +++ b/src/plugins/data_source_management/public/service/data_source_selection_service.test.ts @@ -45,4 +45,16 @@ describe('DataSourceSelectionService service', () => { done(); }); }); + + it('should not store same id selection after calling remove', () => { + const dataSourceSelection = new DataSourceSelectionService(); + const id = generateComponentId(); + const dataSource = { id: 'id', label: 'label' }; + dataSourceSelection.selectDataSource(id, [dataSource]); + expect(dataSourceSelection.getSelectionValue().get(id)).toStrictEqual([dataSource]); + dataSourceSelection.remove(id); + expect(dataSourceSelection.getSelectionValue().get(id)).toStrictEqual(undefined); + dataSourceSelection.selectDataSource(id, [dataSource]); + expect(dataSourceSelection.getSelectionValue().get(id)).toStrictEqual(undefined); + }); }); diff --git a/src/plugins/data_source_management/public/service/data_source_selection_service.ts b/src/plugins/data_source_management/public/service/data_source_selection_service.ts index 560216d88c3a..ced8c8e0c5cc 100644 --- a/src/plugins/data_source_management/public/service/data_source_selection_service.ts +++ b/src/plugins/data_source_management/public/service/data_source_selection_service.ts @@ -8,14 +8,21 @@ import { DataSourceOption } from '../components/data_source_menu/types'; export class DataSourceSelectionService { private selectedDataSource$ = new BehaviorSubject(new Map()); + // Some components may call onSelect function in promise.then, which could be executed later than componentWillUnmount. + // Use this array to record unmounted component IDs to fallback. + private removedComponentIds: string[] = []; public selectDataSource = (componentId: string, dataSource: DataSourceOption[]) => { + if (this.removedComponentIds.indexOf(componentId) > -1) { + return; + } const newMap = new Map(this.selectedDataSource$.value); newMap.set(componentId, dataSource); this.selectedDataSource$.next(newMap); }; public remove = (componentId: string) => { + this.removedComponentIds.push(componentId); const newMap = new Map(this.selectedDataSource$.value); newMap.delete(componentId); this.selectedDataSource$.next(newMap); diff --git a/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu.test.tsx.snap b/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu.test.tsx.snap index 6397e6269129..1825c19d2d3d 100644 --- a/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu.test.tsx.snap +++ b/src/plugins/navigation/public/top_nav_menu/__snapshots__/top_nav_menu.test.tsx.snap @@ -50,6 +50,7 @@ exports[`TopNavMenu mounts the data source menu as well as top nav menu 1`] = ` "getSelection$": [Function], "getSelectionValue": [Function], "remove": [Function], + "removedComponentIds": Array [], "selectDataSource": [Function], "selectedDataSource$": BehaviorSubject { "_isScalar": false, @@ -93,6 +94,7 @@ exports[`TopNavMenu mounts the data source menu if showDataSourceMenu is true 1` "getSelection$": [Function], "getSelectionValue": [Function], "remove": [Function], + "removedComponentIds": Array [], "selectDataSource": [Function], "selectedDataSource$": BehaviorSubject { "_isScalar": false, From e75825106f04aca4be9a48ad72ce382e619ef223 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:00:38 +0800 Subject: [PATCH 005/276] Add server.ssl.cipherSuites to example opensearch_dashboards.yml (#6846) (#6942) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - added server.ssl.cipherSuites to opensearch_dashboards.yml - included a comment describing the parameter and and recommendations about possible values Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as Indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. (cherry picked from commit 080c1fb0078d131617017298059c5570af908684) Signed-off-by: Artur Boryś Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: Lu Yu --- config/opensearch_dashboards.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index dbff317c6d18..95484e787e41 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -88,6 +88,22 @@ # To disregard the validity of SSL certificates, change this setting's value to 'none'. #opensearch.ssl.verificationMode: full +# Allowed cipher suites list can be configured below, in preference order. +# Cipher suite names should be in OpenSSL format (https://www.openssl.org/docs/man1.1.1/man1/ciphers.html#CIPHER-SUITE-NAMES) +# Default set of cipher suites for your system can be checked by running the following command in your terminal: +# echo 'console.log(require("crypto").constants.defaultCoreCipherList.split(":"))' | node - +# Below you can find an example of cipher suites considered to be secure +# Keep in mind that older clients might not support them +# Refer to https://ciphersuite.info/ and https://ssl-config.mozilla.org/ for more details and recommendations about cipher suites +# Keep in mind that restricting cipher suites might disable older versions of TLS, as not all cipher suites are supported by them +#server.ssl.cipherSuites: +# - TLS_AES_256_GCM_SHA384 +# - TLS_CHACHA20_POLY1305_SHA256 +# - TLS_AES_128_GCM_SHA256 +# - ECDHE-ECDSA-AES256-GCM-SHA384 +# - ECDHE-ECDSA-CHACHA20-POLY1305 +# - ECDHE-ECDSA-AES128-GCM-SHA256 + # Time in milliseconds to wait for OpenSearch to respond to pings. Defaults to the value of # the opensearch.requestTimeout setting. #opensearch.pingTimeout: 1500 From 6dbe7d8866bd5c7ccf6b5043beb321b8cb6fdc66 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:01:16 +0800 Subject: [PATCH 006/276] [MDS] Fix sample data to use datasources for TSVB visualizations (#6940) (#6943) * Fix sample data to use datasources for TSVB visualizations * Changeset file for PR #6940 created/updated --------- (cherry picked from commit 61e29b57b33d41c31011df2ff52204552ab739dc) Signed-off-by: Huy Nguyen <73027756+huyaboo@users.noreply.github.com> Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/6940.yml | 2 + .../sample_data/data_sets/util.test.ts | 42 +++++++++++++++++++ .../services/sample_data/data_sets/util.ts | 18 +++++++- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/6940.yml diff --git a/changelogs/fragments/6940.yml b/changelogs/fragments/6940.yml new file mode 100644 index 000000000000..18c34077f389 --- /dev/null +++ b/changelogs/fragments/6940.yml @@ -0,0 +1,2 @@ +fix: +- Add TSVB Support for adding sample data ([#6940](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6940)) \ No newline at end of file diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.test.ts b/src/plugins/home/server/services/sample_data/data_sets/util.test.ts index 1b02fa778f98..c51e289231dc 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/util.test.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/util.test.ts @@ -13,6 +13,19 @@ describe('getSavedObjectsWithDataSource()', () => { return visualizationObjects.saved_objects; }; + const TSVBVisualizationSavedObject = { + type: 'visualization', + id: 'some-id', + attributes: { + title: 'some-title', + visState: JSON.stringify({ + type: 'metrics', + params: {}, + }), + }, + references: [], + }; + test('when processing Vega Visualization saved objects, it should attach data_source_name to each OpenSearch query', () => { const dataSourceId = 'some-datasource-id'; const dataSourceName = 'Data Source Name'; @@ -127,6 +140,35 @@ describe('getSavedObjectsWithDataSource()', () => { }, ]); }); + + test('when processing TSVB Visualization saved objects, it should attach data_source_id to the visState and add datasource reference', () => { + const dataSourceId = 'some-datasource-id'; + const dataSourceTitle = 'Data Source Name'; + const expectedTSVBVisualizationSavedObject = { + ...TSVBVisualizationSavedObject, + id: `${dataSourceId}_some-id`, + attributes: { + title: `some-title_${dataSourceTitle}`, + visState: JSON.stringify({ + type: 'metrics', + params: { + data_source_id: dataSourceId, + }, + }), + }, + references: [ + { + id: dataSourceId, + type: 'data-source', + name: 'dataSource', + }, + ], + }; + + expect( + getSavedObjectsWithDataSource([TSVBVisualizationSavedObject], dataSourceId, dataSourceTitle) + ).toMatchObject([expectedTSVBVisualizationSavedObject]); + }); }); describe('getFinalSavedObjects()', () => { diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.ts b/src/plugins/home/server/services/sample_data/data_sets/util.ts index 5585720649dd..871a9574b591 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/util.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/util.ts @@ -96,6 +96,11 @@ export const getSavedObjectsWithDataSource = ( if (saveObject.type === 'visualization') { const vegaSpec = extractVegaSpecFromSavedObject(saveObject); + const visualizationSavedObject = saveObject as SavedObject & { + attributes: { visState: string }; + }; + const visStateObject = JSON.parse(visualizationSavedObject.attributes.visState); + if (!!vegaSpec) { const updatedVegaSpec = updateDataSourceNameInVegaSpec({ spec: vegaSpec, @@ -104,8 +109,6 @@ export const getSavedObjectsWithDataSource = ( spacing: 1, }); - // @ts-expect-error - const visStateObject = JSON.parse(saveObject.attributes?.visState); visStateObject.params.spec = updatedVegaSpec; // @ts-expect-error @@ -131,6 +134,17 @@ export const getSavedObjectsWithDataSource = ( // @ts-expect-error saveObject.attributes.visState = JSON.stringify(timelineStateObject); } + + if (visStateObject.type === 'metrics') { + visStateObject.params.data_source_id = dataSourceId; + + visualizationSavedObject.attributes.visState = JSON.stringify(visStateObject); + visualizationSavedObject.references.push({ + id: `${dataSourceId}`, + type: 'data-source', + name: 'dataSource', + }); + } } } From 453e579ccf6920a190e32372a859a57ed658e0ba Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 10:25:56 -0700 Subject: [PATCH 007/276] Update json5 dependency (#6937) (#6946) * Update json5 * Update changelog * Revert "Update changelog" This reverts commit 526e0bb89eecaf03a506f80c3c365839fe1467bf. --------- (cherry picked from commit 9674147508c2165fd8429a2fb3bb7b42250a5e13) Signed-off-by: Simeon Widdis Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: Lu Yu --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 59b2f89d0198..a0d2a58e445f 100644 --- a/package.json +++ b/package.json @@ -417,7 +417,7 @@ "jimp": "^0.14.0", "jquery": "^3.5.0", "json-stringify-pretty-compact": "1.2.0", - "json5": "^1.0.1", + "json5": "^2.2.3", "leaflet": "1.5.1", "leaflet-draw": "0.4.14", "leaflet-responsive-popup": "0.6.4", From c0d0b7e5a1548b11593db0134445b64c3203acf8 Mon Sep 17 00:00:00 2001 From: Yu Jin <112784385+yujin-emma@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:03:52 -0700 Subject: [PATCH 008/276] Manual backport #6903 (#6952) Signed-off-by: yujin-emma --- .../opensearch_search_strategy.test.ts | 2 +- .../data_source/common/data_sources/error.ts | 42 +++++++++++++++++++ .../data_source/common/data_sources/types.ts | 2 + .../data_source/opensearch_dashboards.json | 2 +- src/plugins/data_source/server/index.ts | 1 + .../data_source/server/lib/error.test.ts | 3 +- src/plugins/data_source/server/lib/error.ts | 38 +---------------- src/plugins/data_source/server/types.ts | 2 +- .../public/components/utils.test.ts | 25 +++++++++-- .../public/components/utils.ts | 7 +++- .../data_source_management/public/mocks.ts | 12 +++++- .../data_source_management/public/types.ts | 1 + 12 files changed, 90 insertions(+), 47 deletions(-) create mode 100644 src/plugins/data_source/common/data_sources/error.ts diff --git a/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.test.ts b/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.test.ts index ae6e1746dab6..9f7cb83a3a1f 100644 --- a/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.test.ts +++ b/src/plugins/data/server/search/opensearch_search/opensearch_search_strategy.test.ts @@ -34,7 +34,7 @@ import { pluginInitializerContextConfigMock, } from '../../../../../core/server/mocks'; import { opensearchSearchStrategyProvider } from './opensearch_search_strategy'; -import { DataSourceError } from '../../../../data_source/server/lib/error'; +import { DataSourceError } from '../../../../data_source/common/data_sources'; import { DataSourcePluginSetup } from '../../../../data_source/server'; import { SearchUsage } from '../collectors'; diff --git a/src/plugins/data_source/common/data_sources/error.ts b/src/plugins/data_source/common/data_sources/error.ts new file mode 100644 index 000000000000..a1e5b83062f5 --- /dev/null +++ b/src/plugins/data_source/common/data_sources/error.ts @@ -0,0 +1,42 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ResponseError } from '@opensearch-project/opensearch/lib/errors'; +import { OsdError } from '../../../opensearch_dashboards_utils/common'; + +export class DataSourceError extends OsdError { + // must have statusCode to avoid route handler in search.ts to return 500 + statusCode: number; + body: any; + + constructor(error: any, context?: string, statusCode?: number) { + let message: string; + if (context) { + message = context; + } else if (isResponseError(error)) { + message = JSON.stringify(error.meta.body); + } else { + message = error.message; + } + + super('Data Source Error: ' + message); + + if (error.body) { + this.body = error.body; + } + + if (statusCode) { + this.statusCode = statusCode; + } else if (error.statusCode) { + this.statusCode = error.statusCode; + } else { + this.statusCode = 400; + } + } +} + +export const isResponseError = (error: any): error is ResponseError => { + return Boolean(error.body && error.statusCode && error.headers); +}; diff --git a/src/plugins/data_source/common/data_sources/types.ts b/src/plugins/data_source/common/data_sources/types.ts index c28b82861b32..7c32264da0eb 100644 --- a/src/plugins/data_source/common/data_sources/types.ts +++ b/src/plugins/data_source/common/data_sources/types.ts @@ -50,3 +50,5 @@ export enum SigV4ServiceName { OpenSearch = 'es', OpenSearchServerless = 'aoss', } + +export { DataSourceError } from './error'; diff --git a/src/plugins/data_source/opensearch_dashboards.json b/src/plugins/data_source/opensearch_dashboards.json index 871858403cf3..56a884109364 100644 --- a/src/plugins/data_source/opensearch_dashboards.json +++ b/src/plugins/data_source/opensearch_dashboards.json @@ -4,7 +4,7 @@ "opensearchDashboardsVersion": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": [], + "requiredPlugins": ["opensearchDashboardsUtils"], "optionalPlugins": [], "extraPublicDirs": ["common/data_sources"] } diff --git a/src/plugins/data_source/server/index.ts b/src/plugins/data_source/server/index.ts index 156b76066fbb..b0564dfcedc7 100644 --- a/src/plugins/data_source/server/index.ts +++ b/src/plugins/data_source/server/index.ts @@ -24,4 +24,5 @@ export { DataSourcePluginSetup, DataSourcePluginStart, DataSourcePluginRequestContext, + DataSourceError, } from './types'; diff --git a/src/plugins/data_source/server/lib/error.test.ts b/src/plugins/data_source/server/lib/error.test.ts index f4f6cf241769..02ca301fcd1e 100644 --- a/src/plugins/data_source/server/lib/error.test.ts +++ b/src/plugins/data_source/server/lib/error.test.ts @@ -10,7 +10,8 @@ import { ResponseError, } from '@opensearch-project/opensearch-next/lib/errors'; import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; -import { createDataSourceError, DataSourceError } from './error'; +import { createDataSourceError } from './error'; +import { DataSourceError } from '../../common/data_sources'; import { errors as LegacyErrors } from 'elasticsearch'; const createApiResponseError = ({ diff --git a/src/plugins/data_source/server/lib/error.ts b/src/plugins/data_source/server/lib/error.ts index 8bb9e6ba45fa..d0cb8b760622 100644 --- a/src/plugins/data_source/server/lib/error.ts +++ b/src/plugins/data_source/server/lib/error.ts @@ -3,41 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { ResponseError } from '@opensearch-project/opensearch-next/lib/errors'; import { errors as LegacyErrors } from 'elasticsearch'; import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; -import { OsdError } from '../../../opensearch_dashboards_utils/common'; - -export class DataSourceError extends OsdError { - // must have statusCode to avoid route handler in search.ts to return 500 - statusCode: number; - body: any; - - constructor(error: any, context?: string, statusCode?: number) { - let message: string; - if (context) { - message = context; - } else if (isResponseError(error)) { - message = JSON.stringify(error.meta.body); - } else { - message = error.message; - } - - super('Data Source Error: ' + message); - - if (error.body) { - this.body = error.body; - } - - if (statusCode) { - this.statusCode = statusCode; - } else if (error.statusCode) { - this.statusCode = error.statusCode; - } else { - this.statusCode = 400; - } - } -} +import { DataSourceError, isResponseError } from '../../common/data_sources/error'; export const createDataSourceError = (error: any, message?: string): DataSourceError => { // handle saved object client error, while retrieve data source meta info @@ -58,7 +26,3 @@ export const createDataSourceError = (error: any, message?: string): DataSourceE // handle all other error that may or may not comes with statuscode return new DataSourceError(error, message); }; - -const isResponseError = (error: any): error is ResponseError => { - return Boolean(error.body && error.statusCode && error.headers); -}; diff --git a/src/plugins/data_source/server/types.ts b/src/plugins/data_source/server/types.ts index 1f7d297c8b87..e7dd0efd5d0b 100644 --- a/src/plugins/data_source/server/types.ts +++ b/src/plugins/data_source/server/types.ts @@ -17,7 +17,7 @@ import { } from '../common/data_sources'; import { CryptographyServiceSetup } from './cryptography_service'; -import { DataSourceError } from './lib/error'; +import { DataSourceError } from '../common/data_sources'; import { IAuthenticationMethodRegistry } from './auth_registry'; import { CustomApiSchemaRegistry } from './schema_registry'; diff --git a/src/plugins/data_source_management/public/components/utils.test.ts b/src/plugins/data_source_management/public/components/utils.test.ts index 1599454e7a1f..aa73a67d3577 100644 --- a/src/plugins/data_source_management/public/components/utils.test.ts +++ b/src/plugins/data_source_management/public/components/utils.test.ts @@ -38,7 +38,8 @@ import { getSingleDataSourceResponse, getDataSource, getDataSourceOptions, - getDataSourceByIdWithError, + getDataSourceByIdWithNotFoundError, + getDataSourceByIdWithNetworkError, } from '../mocks'; import { AuthType, @@ -166,12 +167,28 @@ describe('DataSourceManagement: Utils.ts', () => { expect(e).toBeTruthy(); } }); - test('failure: gets error when response contains error', async () => { + test('failure: gets error when response contains not found error', async () => { try { - mockResponseForSavedObjectsCalls(savedObjects.client, 'get', getDataSourceByIdWithError); + mockResponseForSavedObjectsCalls( + savedObjects.client, + 'get', + getDataSourceByIdWithNotFoundError + ); await getDataSourceById('alpha-test', savedObjects.client); } catch (e) { - expect(e).toBeTruthy(); + expect(e.statusCode).toBe(404); + } + }); + test('failure: gets error when response contains other error', async () => { + try { + mockResponseForSavedObjectsCalls( + savedObjects.client, + 'get', + getDataSourceByIdWithNetworkError + ); + await getDataSourceById('alpha-test', savedObjects.client); + } catch (e) { + expect(e.statusCode).toBe(500); } }); }); diff --git a/src/plugins/data_source_management/public/components/utils.ts b/src/plugins/data_source_management/public/components/utils.ts index 1ace30bd8eae..4f2db696f950 100644 --- a/src/plugins/data_source_management/public/components/utils.ts +++ b/src/plugins/data_source_management/public/components/utils.ts @@ -37,6 +37,7 @@ import { DataSourceSelectionService, defaultDataSourceSelection, } from '../service/data_source_selection_service'; +import { DataSourceError } from '../types'; export async function getDataSources(savedObjectsClient: SavedObjectsClientContract) { return savedObjectsClient @@ -186,7 +187,11 @@ export async function getDataSourceById( const response = await savedObjectsClient.get('data-source', id); if (!response || response.error) { - throw new Error('Unable to find data source'); + const statusCode = response.error?.statusCode; + if (statusCode === 404) { + throw new DataSourceError({ statusCode, body: 'Unable to find data source' }); + } + throw new DataSourceError({ statusCode, body: response.error?.message }); } const attributes: any = response?.attributes || {}; diff --git a/src/plugins/data_source_management/public/mocks.ts b/src/plugins/data_source_management/public/mocks.ts index abc4af28dd4c..696700196d7b 100644 --- a/src/plugins/data_source_management/public/mocks.ts +++ b/src/plugins/data_source_management/public/mocks.ts @@ -331,7 +331,7 @@ export const getDataSourceByIdWithoutCredential = { references: [], }; -export const getDataSourceByIdWithError = { +export const getDataSourceByIdWithNotFoundError = { attributes: { ...getDataSourceByIdWithCredential.attributes, Error: { @@ -341,6 +341,16 @@ export const getDataSourceByIdWithError = { }, references: [], }; +export const getDataSourceByIdWithNetworkError = { + attributes: { + ...getDataSourceByIdWithCredential.attributes, + Error: { + statusCode: 500, + errorMessage: 'Internal server error', + }, + }, + references: [], +}; export const mockResponseForSavedObjectsCalls = ( savedObjectsClient: SavedObjectsClientContract, diff --git a/src/plugins/data_source_management/public/types.ts b/src/plugins/data_source_management/public/types.ts index d7c3dfe213fa..f0fa1790cd8f 100644 --- a/src/plugins/data_source_management/public/types.ts +++ b/src/plugins/data_source_management/public/types.ts @@ -139,4 +139,5 @@ export { UsernamePasswordTypedContent, SigV4Content, DataSourceAttributes, + DataSourceError, } from '../../data_source/common/data_sources'; From ffc50aa4ef2d83787c439aa23ad2ea18daac7fda Mon Sep 17 00:00:00 2001 From: Miki Date: Thu, 6 Jun 2024 17:36:51 -0700 Subject: [PATCH 009/276] Cleanup yarn.lock (#6951) Signed-off-by: Miki --- packages/osd-pm/dist/index.js | 67 +++-- yarn.lock | 475 +++------------------------------- 2 files changed, 92 insertions(+), 450 deletions(-) diff --git a/packages/osd-pm/dist/index.js b/packages/osd-pm/dist/index.js index 458aacd2256c..fcb50d8f06c9 100644 --- a/packages/osd-pm/dist/index.js +++ b/packages/osd-pm/dist/index.js @@ -24189,7 +24189,7 @@ module.exports = function (x, opts) { "use strict"; -var has = __webpack_require__(263); +var hasOwn = __webpack_require__(263); function specifierIncluded(current, specifier) { var nodeParts = current.split('.'); @@ -24254,7 +24254,7 @@ function versionIncluded(nodeVersion, specifierValue) { var data = __webpack_require__(266); module.exports = function isCore(x, nodeVersion) { - return has(data, x) && versionIncluded(nodeVersion, data[x]); + return hasOwn(data, x) && versionIncluded(nodeVersion, data[x]); }; @@ -24265,9 +24265,12 @@ module.exports = function isCore(x, nodeVersion) { "use strict"; +var call = Function.prototype.call; +var $hasOwn = Object.prototype.hasOwnProperty; var bind = __webpack_require__(264); -module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty); +/** @type {(o: {}, p: PropertyKey) => p is keyof o} */ +module.exports = bind.call(call, $hasOwn); /***/ }), @@ -24292,43 +24295,75 @@ module.exports = Function.prototype.bind || implementation; /* eslint no-invalid-this: 1 */ var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; -var slice = Array.prototype.slice; var toStr = Object.prototype.toString; +var max = Math.max; var funcType = '[object Function]'; +var concatty = function concatty(a, b) { + var arr = []; + + for (var i = 0; i < a.length; i += 1) { + arr[i] = a[i]; + } + for (var j = 0; j < b.length; j += 1) { + arr[j + a.length] = b[j]; + } + + return arr; +}; + +var slicy = function slicy(arrLike, offset) { + var arr = []; + for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) { + arr[j] = arrLike[i]; + } + return arr; +}; + +var joiny = function (arr, joiner) { + var str = ''; + for (var i = 0; i < arr.length; i += 1) { + str += arr[i]; + if (i + 1 < arr.length) { + str += joiner; + } + } + return str; +}; + module.exports = function bind(that) { var target = this; - if (typeof target !== 'function' || toStr.call(target) !== funcType) { + if (typeof target !== 'function' || toStr.apply(target) !== funcType) { throw new TypeError(ERROR_MESSAGE + target); } - var args = slice.call(arguments, 1); + var args = slicy(arguments, 1); var bound; var binder = function () { if (this instanceof bound) { var result = target.apply( this, - args.concat(slice.call(arguments)) + concatty(args, arguments) ); if (Object(result) === result) { return result; } return this; - } else { - return target.apply( - that, - args.concat(slice.call(arguments)) - ); } + return target.apply( + that, + concatty(args, arguments) + ); + }; - var boundLength = Math.max(0, target.length - args.length); + var boundLength = max(0, target.length - args.length); var boundArgs = []; for (var i = 0; i < boundLength; i++) { - boundArgs.push('$' + i); + boundArgs[i] = '$' + i; } - bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); + bound = Function('binder', 'return function (' + joiny(boundArgs, ',') + '){ return binder.apply(this,arguments); }')(binder); if (target.prototype) { var Empty = function Empty() {}; @@ -24345,7 +24380,7 @@ module.exports = function bind(that) { /* 266 */ /***/ (function(module) { -module.exports = JSON.parse("{\"assert\":true,\"node:assert\":[\">= 14.18 && < 15\",\">= 16\"],\"assert/strict\":\">= 15\",\"node:assert/strict\":\">= 16\",\"async_hooks\":\">= 8\",\"node:async_hooks\":[\">= 14.18 && < 15\",\">= 16\"],\"buffer_ieee754\":\">= 0.5 && < 0.9.7\",\"buffer\":true,\"node:buffer\":[\">= 14.18 && < 15\",\">= 16\"],\"child_process\":true,\"node:child_process\":[\">= 14.18 && < 15\",\">= 16\"],\"cluster\":\">= 0.5\",\"node:cluster\":[\">= 14.18 && < 15\",\">= 16\"],\"console\":true,\"node:console\":[\">= 14.18 && < 15\",\">= 16\"],\"constants\":true,\"node:constants\":[\">= 14.18 && < 15\",\">= 16\"],\"crypto\":true,\"node:crypto\":[\">= 14.18 && < 15\",\">= 16\"],\"_debug_agent\":\">= 1 && < 8\",\"_debugger\":\"< 8\",\"dgram\":true,\"node:dgram\":[\">= 14.18 && < 15\",\">= 16\"],\"diagnostics_channel\":[\">= 14.17 && < 15\",\">= 15.1\"],\"node:diagnostics_channel\":[\">= 14.18 && < 15\",\">= 16\"],\"dns\":true,\"node:dns\":[\">= 14.18 && < 15\",\">= 16\"],\"dns/promises\":\">= 15\",\"node:dns/promises\":\">= 16\",\"domain\":\">= 0.7.12\",\"node:domain\":[\">= 14.18 && < 15\",\">= 16\"],\"events\":true,\"node:events\":[\">= 14.18 && < 15\",\">= 16\"],\"freelist\":\"< 6\",\"fs\":true,\"node:fs\":[\">= 14.18 && < 15\",\">= 16\"],\"fs/promises\":[\">= 10 && < 10.1\",\">= 14\"],\"node:fs/promises\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_agent\":\">= 0.11.1\",\"node:_http_agent\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_client\":\">= 0.11.1\",\"node:_http_client\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_common\":\">= 0.11.1\",\"node:_http_common\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_incoming\":\">= 0.11.1\",\"node:_http_incoming\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_outgoing\":\">= 0.11.1\",\"node:_http_outgoing\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_server\":\">= 0.11.1\",\"node:_http_server\":[\">= 14.18 && < 15\",\">= 16\"],\"http\":true,\"node:http\":[\">= 14.18 && < 15\",\">= 16\"],\"http2\":\">= 8.8\",\"node:http2\":[\">= 14.18 && < 15\",\">= 16\"],\"https\":true,\"node:https\":[\">= 14.18 && < 15\",\">= 16\"],\"inspector\":\">= 8\",\"node:inspector\":[\">= 14.18 && < 15\",\">= 16\"],\"inspector/promises\":[\">= 19\"],\"node:inspector/promises\":[\">= 19\"],\"_linklist\":\"< 8\",\"module\":true,\"node:module\":[\">= 14.18 && < 15\",\">= 16\"],\"net\":true,\"node:net\":[\">= 14.18 && < 15\",\">= 16\"],\"node-inspect/lib/_inspect\":\">= 7.6 && < 12\",\"node-inspect/lib/internal/inspect_client\":\">= 7.6 && < 12\",\"node-inspect/lib/internal/inspect_repl\":\">= 7.6 && < 12\",\"os\":true,\"node:os\":[\">= 14.18 && < 15\",\">= 16\"],\"path\":true,\"node:path\":[\">= 14.18 && < 15\",\">= 16\"],\"path/posix\":\">= 15.3\",\"node:path/posix\":\">= 16\",\"path/win32\":\">= 15.3\",\"node:path/win32\":\">= 16\",\"perf_hooks\":\">= 8.5\",\"node:perf_hooks\":[\">= 14.18 && < 15\",\">= 16\"],\"process\":\">= 1\",\"node:process\":[\">= 14.18 && < 15\",\">= 16\"],\"punycode\":\">= 0.5\",\"node:punycode\":[\">= 14.18 && < 15\",\">= 16\"],\"querystring\":true,\"node:querystring\":[\">= 14.18 && < 15\",\">= 16\"],\"readline\":true,\"node:readline\":[\">= 14.18 && < 15\",\">= 16\"],\"readline/promises\":\">= 17\",\"node:readline/promises\":\">= 17\",\"repl\":true,\"node:repl\":[\">= 14.18 && < 15\",\">= 16\"],\"smalloc\":\">= 0.11.5 && < 3\",\"_stream_duplex\":\">= 0.9.4\",\"node:_stream_duplex\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_transform\":\">= 0.9.4\",\"node:_stream_transform\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_wrap\":\">= 1.4.1\",\"node:_stream_wrap\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_passthrough\":\">= 0.9.4\",\"node:_stream_passthrough\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_readable\":\">= 0.9.4\",\"node:_stream_readable\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_writable\":\">= 0.9.4\",\"node:_stream_writable\":[\">= 14.18 && < 15\",\">= 16\"],\"stream\":true,\"node:stream\":[\">= 14.18 && < 15\",\">= 16\"],\"stream/consumers\":\">= 16.7\",\"node:stream/consumers\":\">= 16.7\",\"stream/promises\":\">= 15\",\"node:stream/promises\":\">= 16\",\"stream/web\":\">= 16.5\",\"node:stream/web\":\">= 16.5\",\"string_decoder\":true,\"node:string_decoder\":[\">= 14.18 && < 15\",\">= 16\"],\"sys\":[\">= 0.4 && < 0.7\",\">= 0.8\"],\"node:sys\":[\">= 14.18 && < 15\",\">= 16\"],\"node:test\":[\">= 16.17 && < 17\",\">= 18\"],\"timers\":true,\"node:timers\":[\">= 14.18 && < 15\",\">= 16\"],\"timers/promises\":\">= 15\",\"node:timers/promises\":\">= 16\",\"_tls_common\":\">= 0.11.13\",\"node:_tls_common\":[\">= 14.18 && < 15\",\">= 16\"],\"_tls_legacy\":\">= 0.11.3 && < 10\",\"_tls_wrap\":\">= 0.11.3\",\"node:_tls_wrap\":[\">= 14.18 && < 15\",\">= 16\"],\"tls\":true,\"node:tls\":[\">= 14.18 && < 15\",\">= 16\"],\"trace_events\":\">= 10\",\"node:trace_events\":[\">= 14.18 && < 15\",\">= 16\"],\"tty\":true,\"node:tty\":[\">= 14.18 && < 15\",\">= 16\"],\"url\":true,\"node:url\":[\">= 14.18 && < 15\",\">= 16\"],\"util\":true,\"node:util\":[\">= 14.18 && < 15\",\">= 16\"],\"util/types\":\">= 15.3\",\"node:util/types\":\">= 16\",\"v8/tools/arguments\":\">= 10 && < 12\",\"v8/tools/codemap\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/consarray\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/csvparser\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/logreader\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/profile_view\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/splaytree\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8\":\">= 1\",\"node:v8\":[\">= 14.18 && < 15\",\">= 16\"],\"vm\":true,\"node:vm\":[\">= 14.18 && < 15\",\">= 16\"],\"wasi\":\">= 13.4 && < 13.5\",\"worker_threads\":\">= 11.7\",\"node:worker_threads\":[\">= 14.18 && < 15\",\">= 16\"],\"zlib\":\">= 0.5\",\"node:zlib\":[\">= 14.18 && < 15\",\">= 16\"]}"); +module.exports = JSON.parse("{\"assert\":true,\"node:assert\":[\">= 14.18 && < 15\",\">= 16\"],\"assert/strict\":\">= 15\",\"node:assert/strict\":\">= 16\",\"async_hooks\":\">= 8\",\"node:async_hooks\":[\">= 14.18 && < 15\",\">= 16\"],\"buffer_ieee754\":\">= 0.5 && < 0.9.7\",\"buffer\":true,\"node:buffer\":[\">= 14.18 && < 15\",\">= 16\"],\"child_process\":true,\"node:child_process\":[\">= 14.18 && < 15\",\">= 16\"],\"cluster\":\">= 0.5\",\"node:cluster\":[\">= 14.18 && < 15\",\">= 16\"],\"console\":true,\"node:console\":[\">= 14.18 && < 15\",\">= 16\"],\"constants\":true,\"node:constants\":[\">= 14.18 && < 15\",\">= 16\"],\"crypto\":true,\"node:crypto\":[\">= 14.18 && < 15\",\">= 16\"],\"_debug_agent\":\">= 1 && < 8\",\"_debugger\":\"< 8\",\"dgram\":true,\"node:dgram\":[\">= 14.18 && < 15\",\">= 16\"],\"diagnostics_channel\":[\">= 14.17 && < 15\",\">= 15.1\"],\"node:diagnostics_channel\":[\">= 14.18 && < 15\",\">= 16\"],\"dns\":true,\"node:dns\":[\">= 14.18 && < 15\",\">= 16\"],\"dns/promises\":\">= 15\",\"node:dns/promises\":\">= 16\",\"domain\":\">= 0.7.12\",\"node:domain\":[\">= 14.18 && < 15\",\">= 16\"],\"events\":true,\"node:events\":[\">= 14.18 && < 15\",\">= 16\"],\"freelist\":\"< 6\",\"fs\":true,\"node:fs\":[\">= 14.18 && < 15\",\">= 16\"],\"fs/promises\":[\">= 10 && < 10.1\",\">= 14\"],\"node:fs/promises\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_agent\":\">= 0.11.1\",\"node:_http_agent\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_client\":\">= 0.11.1\",\"node:_http_client\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_common\":\">= 0.11.1\",\"node:_http_common\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_incoming\":\">= 0.11.1\",\"node:_http_incoming\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_outgoing\":\">= 0.11.1\",\"node:_http_outgoing\":[\">= 14.18 && < 15\",\">= 16\"],\"_http_server\":\">= 0.11.1\",\"node:_http_server\":[\">= 14.18 && < 15\",\">= 16\"],\"http\":true,\"node:http\":[\">= 14.18 && < 15\",\">= 16\"],\"http2\":\">= 8.8\",\"node:http2\":[\">= 14.18 && < 15\",\">= 16\"],\"https\":true,\"node:https\":[\">= 14.18 && < 15\",\">= 16\"],\"inspector\":\">= 8\",\"node:inspector\":[\">= 14.18 && < 15\",\">= 16\"],\"inspector/promises\":[\">= 19\"],\"node:inspector/promises\":[\">= 19\"],\"_linklist\":\"< 8\",\"module\":true,\"node:module\":[\">= 14.18 && < 15\",\">= 16\"],\"net\":true,\"node:net\":[\">= 14.18 && < 15\",\">= 16\"],\"node-inspect/lib/_inspect\":\">= 7.6 && < 12\",\"node-inspect/lib/internal/inspect_client\":\">= 7.6 && < 12\",\"node-inspect/lib/internal/inspect_repl\":\">= 7.6 && < 12\",\"os\":true,\"node:os\":[\">= 14.18 && < 15\",\">= 16\"],\"path\":true,\"node:path\":[\">= 14.18 && < 15\",\">= 16\"],\"path/posix\":\">= 15.3\",\"node:path/posix\":\">= 16\",\"path/win32\":\">= 15.3\",\"node:path/win32\":\">= 16\",\"perf_hooks\":\">= 8.5\",\"node:perf_hooks\":[\">= 14.18 && < 15\",\">= 16\"],\"process\":\">= 1\",\"node:process\":[\">= 14.18 && < 15\",\">= 16\"],\"punycode\":\">= 0.5\",\"node:punycode\":[\">= 14.18 && < 15\",\">= 16\"],\"querystring\":true,\"node:querystring\":[\">= 14.18 && < 15\",\">= 16\"],\"readline\":true,\"node:readline\":[\">= 14.18 && < 15\",\">= 16\"],\"readline/promises\":\">= 17\",\"node:readline/promises\":\">= 17\",\"repl\":true,\"node:repl\":[\">= 14.18 && < 15\",\">= 16\"],\"smalloc\":\">= 0.11.5 && < 3\",\"_stream_duplex\":\">= 0.9.4\",\"node:_stream_duplex\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_transform\":\">= 0.9.4\",\"node:_stream_transform\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_wrap\":\">= 1.4.1\",\"node:_stream_wrap\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_passthrough\":\">= 0.9.4\",\"node:_stream_passthrough\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_readable\":\">= 0.9.4\",\"node:_stream_readable\":[\">= 14.18 && < 15\",\">= 16\"],\"_stream_writable\":\">= 0.9.4\",\"node:_stream_writable\":[\">= 14.18 && < 15\",\">= 16\"],\"stream\":true,\"node:stream\":[\">= 14.18 && < 15\",\">= 16\"],\"stream/consumers\":\">= 16.7\",\"node:stream/consumers\":\">= 16.7\",\"stream/promises\":\">= 15\",\"node:stream/promises\":\">= 16\",\"stream/web\":\">= 16.5\",\"node:stream/web\":\">= 16.5\",\"string_decoder\":true,\"node:string_decoder\":[\">= 14.18 && < 15\",\">= 16\"],\"sys\":[\">= 0.4 && < 0.7\",\">= 0.8\"],\"node:sys\":[\">= 14.18 && < 15\",\">= 16\"],\"test/reporters\":\">= 19.9 && < 20.2\",\"node:test/reporters\":[\">= 18.17 && < 19\",\">= 19.9\",\">= 20\"],\"node:test\":[\">= 16.17 && < 17\",\">= 18\"],\"timers\":true,\"node:timers\":[\">= 14.18 && < 15\",\">= 16\"],\"timers/promises\":\">= 15\",\"node:timers/promises\":\">= 16\",\"_tls_common\":\">= 0.11.13\",\"node:_tls_common\":[\">= 14.18 && < 15\",\">= 16\"],\"_tls_legacy\":\">= 0.11.3 && < 10\",\"_tls_wrap\":\">= 0.11.3\",\"node:_tls_wrap\":[\">= 14.18 && < 15\",\">= 16\"],\"tls\":true,\"node:tls\":[\">= 14.18 && < 15\",\">= 16\"],\"trace_events\":\">= 10\",\"node:trace_events\":[\">= 14.18 && < 15\",\">= 16\"],\"tty\":true,\"node:tty\":[\">= 14.18 && < 15\",\">= 16\"],\"url\":true,\"node:url\":[\">= 14.18 && < 15\",\">= 16\"],\"util\":true,\"node:util\":[\">= 14.18 && < 15\",\">= 16\"],\"util/types\":\">= 15.3\",\"node:util/types\":\">= 16\",\"v8/tools/arguments\":\">= 10 && < 12\",\"v8/tools/codemap\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/consarray\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/csvparser\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/logreader\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/profile_view\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8/tools/splaytree\":[\">= 4.4 && < 5\",\">= 5.2 && < 12\"],\"v8\":\">= 1\",\"node:v8\":[\">= 14.18 && < 15\",\">= 16\"],\"vm\":true,\"node:vm\":[\">= 14.18 && < 15\",\">= 16\"],\"wasi\":[\">= 13.4 && < 13.5\",\">= 18.17 && < 19\",\">= 20\"],\"node:wasi\":[\">= 18.17 && < 19\",\">= 20\"],\"worker_threads\":\">= 11.7\",\"node:worker_threads\":[\">= 14.18 && < 15\",\">= 16\"],\"zlib\":\">= 0.5\",\"node:zlib\":[\">= 14.18 && < 15\",\">= 16\"]}"); /***/ }), /* 267 */ diff --git a/yarn.lock b/yarn.lock index ff9c7b670574..16143fcd97ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1175,20 +1175,13 @@ core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.22.9", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.22.9", "@babel/runtime@^7.23.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== dependencies: regenerator-runtime "^0.14.0" -"@babel/runtime@^7.23.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" - integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== - dependencies: - regenerator-runtime "^0.14.0" - "@babel/template@^7.22.15", "@babel/template@^7.3.3": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" @@ -2251,12 +2244,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.11" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" - integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== - -"@jridgewell/sourcemap-codec@^1.4.14": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -4707,16 +4695,7 @@ array.prototype.filter@^1.0.0: es-array-method-boxes-properly "^1.0.0" is-string "^1.0.7" -array.prototype.find@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.1.2.tgz#6abbd0c2573925d8094f7d23112306af8c16d534" - integrity sha512-00S1O4ewO95OmmJW7EesWfQlrCrLEL8kZ40w3+GkLX2yTt0m2ggcePPa2uHPJ9KUmJvwRq+lCV9bD8Yim23x/Q== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - -array.prototype.find@^2.2.2: +array.prototype.find@^2.1.1, array.prototype.find@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.2.2.tgz#e862cf891e725d8f2a10e5e42d750629faaabd32" integrity sha512-DRumkfW97iZGOfn+lIXbkVrXL04sfYKX+EfOodo8XboR5sxPDVvOjZTF/rysusa9lmhmSOeD6Vp6RKQP+eP4Tg== @@ -4886,26 +4865,10 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -aws-sdk@^2.650.0: - version "2.1214.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1214.0.tgz#6a57945b5bc9db79f8ee5ed99128a06110a88f83" - integrity sha512-50WxqYgEDB5UxwPJ0IDFWXe3ipAHhHmqfRnMNaQaZhb2aJpprbT7c0zic8AH9E1xJ9s+6QkhYrwQf/vXEHnLwg== - dependencies: - buffer "4.9.2" - events "1.1.1" - ieee754 "1.1.13" - jmespath "0.16.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - util "^0.12.4" - uuid "8.0.0" - xml2js "0.4.19" - -aws-sdk@^2.814.0: - version "2.1319.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1319.0.tgz#be1d91fcac13262fa106f0f0a15ee07c023972fd" - integrity sha512-/gPCVsCARitph9FmBTXZmzjX0Br8LwBfu2MTNPGjVCiZkEUSoUWAAigIWkvrjTWOXCI7TSElRwtCzlsVHdv5VA== +aws-sdk@^2.650.0, aws-sdk@^2.814.0: + version "2.1271.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1271.0.tgz#a060fe65ff33afddb7385913200df4a26717f691" + integrity sha512-hQF+mjwe2FXFKOMNQGlfqn9InIL1bRp650ftctRqDo+VpnrYnKqF9eZa5Hk2kugs3/WUa4J2aqQa+foGWeH+Fg== dependencies: buffer "4.9.2" events "1.1.1" @@ -5207,12 +5170,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - -bn.js@^5.2.1: +bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== @@ -5341,27 +5299,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@*, browserslist@^4.21.10: - version "4.21.10" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" - integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== - dependencies: - caniuse-lite "^1.0.30001517" - electron-to-chromium "^1.4.477" - node-releases "^2.0.13" - update-browserslist-db "^1.0.11" - -browserslist@^4.21.5: - version "4.21.9" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635" - integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg== - dependencies: - caniuse-lite "^1.0.30001503" - electron-to-chromium "^1.4.431" - node-releases "^2.0.12" - update-browserslist-db "^1.0.11" - -browserslist@^4.21.9, browserslist@^4.22.1: +browserslist@*, browserslist@^4.21.10, browserslist@^4.21.5, browserslist@^4.21.9, browserslist@^4.22.1: version "4.22.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== @@ -5550,15 +5488,7 @@ caching-transform@^4.0.0: package-hash "^4.0.0" write-file-atomic "^3.0.0" -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -call-bind@^1.0.4, call-bind@^1.0.5: +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== @@ -5601,7 +5531,7 @@ camelize@^1.0.0: resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= -caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001503, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001541: +caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001541: version "1.0.30001587" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz" integrity sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA== @@ -6894,12 +6824,7 @@ decamelize@^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" - integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== - -decimal.js@^10.4.3: +decimal.js@^10.2.1, decimal.js@^10.4.3: version "10.4.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== @@ -6992,22 +6917,7 @@ define-data-property@^1.0.1, define-data-property@^1.1.1: gopd "^1.0.1" has-property-descriptors "^1.0.0" -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== - dependencies: - object-keys "^1.0.12" - -define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== - dependencies: - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -define-properties@^1.2.0: +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -7175,15 +7085,7 @@ detective@^5.0.2: defined "^1.0.0" minimist "^1.1.1" -dezalgo@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= - dependencies: - asap "^2.0.0" - wrappy "1" - -dezalgo@^1.0.4: +dezalgo@^1.0.0, dezalgo@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig== @@ -7477,16 +7379,6 @@ elasticsearch@^16.4.0, elasticsearch@^16.7.0: chalk "^1.0.0" lodash "^4.17.10" -electron-to-chromium@^1.4.431: - version "1.4.477" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.477.tgz#05669aa6f161ee9076a6805457e9bd9fe6d0dfd1" - integrity sha512-shUVy6Eawp33dFBFIoYbIwLHrX0IZ857AlH9ug2o4rvbWmpaCUdBpQ5Zw39HRrfzAFm4APJE9V+E2A/WB0YqJw== - -electron-to-chromium@^1.4.477: - version "1.4.482" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.482.tgz#77c5ed37b93d4dda860e27538e0e2a01d6a19e02" - integrity sha512-h+UqpfmEr1Qkk0zp7ej/jid7CXoq4m4QzW6wNTb0ELJ/BZCpA4wgUylBIMGCe621tnr4l5VmoHjdoSx2lbnNJA== - electron-to-chromium@^1.4.535: version "1.4.573" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.573.tgz#aa6e5edf86448bb9398f529357abcc6a17b6341d" @@ -7703,62 +7595,7 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.1.1" -es-abstract@^1.18.5, es-abstract@^1.19.0, es-abstract@^1.19.1: - version "1.19.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.2.tgz#8f7b696d8f15b167ae3640b4060670f3d054143f" - integrity sha512-gfSBJoZdlL2xRiOCy0g8gLMryhoe1TlimjzU99L/31Z8QEGIhVQI+EWwt5lT+AuU9SnorVupXFqqOGqGfsyO6w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.3" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.2" - object-inspect "^1.12.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-abstract@^1.19.5, es-abstract@^1.20.0: - version "1.20.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.2.tgz#8495a07bc56d342a3b8ea3ab01bd986700c2ccb3" - integrity sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.1.2" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-symbols "^1.0.3" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-weakref "^1.0.2" - object-inspect "^1.12.2" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - string.prototype.trimend "^1.0.5" - string.prototype.trimstart "^1.0.5" - unbox-primitive "^1.0.2" - -es-abstract@^1.22.1: +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.22.1: version "1.22.3" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== @@ -8891,11 +8728,6 @@ for-own@^1.0.0: dependencies: for-in "^1.0.1" -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - foreground-child@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" @@ -8947,16 +8779,11 @@ fp-ts@^2.3.1: resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.11.9.tgz#bbc204e0932954b59c98a282635754a4b624a05e" integrity sha512-GhYlNKkCOfdjp71ocdtyaQGoqCswEoWDJLRr+2jClnBBq2dnSOtd6QxmJdALq8UhfqCyZZ0f0lxadU4OhwY9nw== -fraction.js@4.3.4: +fraction.js@4.3.4, fraction.js@^4.2.0: version "4.3.4" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.4.tgz#b2bac8249a610c3396106da97c5a71da75b94b1c" integrity sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q== -fraction.js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" - integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== - fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" @@ -9039,27 +8866,12 @@ 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== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -function-bind@^1.1.2: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.2, function.prototype.name@^1.1.3, function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - -function.prototype.name@^1.1.6: +function.prototype.name@^1.1.2, function.prototype.name@^1.1.3, function.prototype.name@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== @@ -9074,11 +8886,6 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -functions-have-names@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.2.tgz#98d93991c39da9361f8e50b337c4f6e41f120e21" - integrity sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA== - functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -9105,25 +8912,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-intrinsic@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" - integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.3" - -get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: +get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== @@ -9626,12 +9415,7 @@ has-ansi@^3.0.0: dependencies: ansi-regex "^3.0.0" -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-bigints@^1.0.2: +has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== @@ -10170,12 +9954,7 @@ immediate@~3.0.5: resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps= -immer@^9.0.6: - version "9.0.12" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20" - integrity sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA== - -immer@^9.0.7: +immer@^9.0.6, immer@^9.0.7: version "9.0.15" resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.15.tgz#0b9169e5b1d22137aba7d43f8a81a495dd1b62dc" integrity sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ== @@ -10292,16 +10071,7 @@ inquirer@^7.0.0, inquirer@^7.3.3: strip-ansi "^6.0.0" through "^2.3.6" -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -internal-slot@^1.0.5: +internal-slot@^1.0.3, internal-slot@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== @@ -10498,24 +10268,12 @@ is-buffer@^2.0.0: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - -is-callable@^1.2.7: +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.1.0, is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.0, is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== - dependencies: - has "^1.0.3" - -is-core-module@^2.13.0, is-core-module@^2.13.1: +is-core-module@^2.1.0, is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.0, is-core-module@^2.9.0: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== @@ -10793,11 +10551,6 @@ is-set@^2.0.1, is-set@^2.0.2: resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -10834,35 +10587,13 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.3, is-typed-array@^1.1.9: version "1.1.12" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== dependencies: which-typed-array "^1.1.11" -is-typed-array@^1.1.3: - version "1.1.9" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.9.tgz#246d77d2871e7d9f5aeb1d54b9f52c71329ece67" - integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.20.0" - for-each "^0.3.3" - has-tostringtag "^1.0.0" - -is-typed-array@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" - integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -12950,16 +12681,11 @@ nano-css@^5.2.1: stacktrace-js "^2.0.2" stylis "^4.0.6" -nanoid@3.3.3: +nanoid@3.3.3, nanoid@^3.3.1: 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" - integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA== - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -13152,7 +12878,7 @@ node-preload@^0.2.1: dependencies: process-on-spawn "^1.0.0" -node-releases@^2.0.12, node-releases@^2.0.13: +node-releases@^2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== @@ -13331,17 +13057,7 @@ object-identity-map@^1.0.2: dependencies: object.entries "^1.1.0" -object-inspect@^1.12.0, object-inspect@^1.7.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - -object-inspect@^1.12.2: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== - -object-inspect@^1.13.1: +object-inspect@^1.12.0, object-inspect@^1.13.1, object-inspect@^1.7.0, object-inspect@^1.9.0: version "1.13.1" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== @@ -13354,7 +13070,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.12, object-keys@^1.1.1: +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== @@ -13366,17 +13082,7 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -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" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.assign@^4.1.4: +object.assign@^4.0.4, object.assign@^4.1.0, object.assign@^4.1.2, object.assign@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== @@ -14846,10 +14552,10 @@ read-pkg@^5.2.0: string_decoder "~1.1.1" util-deprecate "~1.0.1" -"readable-stream@2 || 3", readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== +"readable-stream@2 || 3", readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0, readable-stream@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" @@ -14865,15 +14571,6 @@ read-pkg@^5.2.0: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^3.6.2: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - readdir-glob@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" @@ -14941,14 +14638,7 @@ redux-thunk@^2.3.0, redux-thunk@^2.4.1: resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.1.tgz#0dd8042cf47868f4b29699941de03c9301a75714" integrity sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q== -redux@^4.0.0, redux@^4.0.4, redux@^4.0.5: - version "4.1.2" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" - integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== - dependencies: - "@babel/runtime" "^7.9.2" - -redux@^4.1.2: +redux@^4.0.0, redux@^4.0.4, redux@^4.0.5, redux@^4.1.2: version "4.2.0" resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.0.tgz#46f10d6e29b6666df758780437651eeb2b969f13" integrity sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA== @@ -15026,24 +14716,7 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" - integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" - -regexp.prototype.flags@^1.5.1: +regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== @@ -15278,12 +14951,7 @@ requires-regex@^0.3.3: resolved "https://registry.yarnpkg.com/requires-regex/-/requires-regex-0.3.3.tgz#60309eaabbfd5ca8259e090b8b5a94b2144eb0dd" integrity sha1-YDCeqrv9XKglngkLi1qUshROsN0= -reselect@^4.0.0: - version "4.1.5" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6" - integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== - -reselect@^4.1.5: +reselect@^4.0.0, reselect@^4.1.5: version "4.1.6" resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.6.tgz#19ca2d3d0b35373a74dc1c98692cdaffb6602656" integrity sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ== @@ -16401,16 +16069,7 @@ string.prototype.matchall@^4.0.6: regexp.prototype.flags "^1.4.1" side-channel "^1.0.4" -string.prototype.trim@^1.2.1, string.prototype.trim@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.5.tgz#a587bcc8bfad8cb9829a577f5de30dd170c1682c" - integrity sha512-Lnh17webJVsD6ECeovpVN17RlAKjmz4rF9S+8Y45CkMc/ufVpTkU3vZIyIC7sllQ1FCvObZnnCdNs/HXTUOTlg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - -string.prototype.trim@^1.2.8: +string.prototype.trim@^1.2.1, string.prototype.trim@^1.2.5, string.prototype.trim@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== @@ -16419,23 +16078,6 @@ string.prototype.trim@^1.2.8: define-properties "^1.2.0" es-abstract "^1.22.1" -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimend@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" - integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.19.5" - string.prototype.trimend@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" @@ -16445,7 +16087,7 @@ string.prototype.trimend@^1.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" -string.prototype.trimstart@^1.0.4, string.prototype.trimstart@^1.0.5, string.prototype.trimstart@^1.0.7: +string.prototype.trimstart@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== @@ -17383,12 +17025,7 @@ type@^1.0.1: resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== -type@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.6.0.tgz#3ca6099af5981d36ca86b78442973694278a219f" - integrity sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ== - -type@^2.7.2: +type@^2.5.0, type@^2.7.2: version "2.7.2" resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== @@ -17469,16 +17106,6 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.4.tgz#fa95c257e88f85614915b906204b9623d4fa340d" integrity sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA== -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" @@ -17726,14 +17353,6 @@ upath@^1.1.1: resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -update-browserslist-db@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - update-browserslist-db@^1.0.13: version "1.0.13" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" @@ -18662,7 +18281,7 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which-typed-array@^1.1.11, which-typed-array@^1.1.13: +which-typed-array@^1.1.11, which-typed-array@^1.1.13, which-typed-array@^1.1.2: version "1.1.13" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== @@ -18673,18 +18292,6 @@ which-typed-array@^1.1.11, which-typed-array@^1.1.13: gopd "^1.0.1" has-tostringtag "^1.0.0" -which-typed-array@^1.1.2: - version "1.1.7" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" - integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.7" - 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" From 150a9d350d72afefa4d5c342de300c0efd243812 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:50:26 -0700 Subject: [PATCH 010/276] Fix web log sample visualization & vis-builder not rendering with data source issue (#6948) (#6958) * Fix web log sample visualization & visbuilder not rendering issue * Changeset file for PR #6948 created/updated --------- (cherry picked from commit 9a6b1bb06556061d74715a6274dbc91610b1970a) Signed-off-by: Zhongnan Su Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/6948.yml | 2 + .../data_sets/logs/saved_objects.ts | 130 ++++-------------- .../services/sample_data/data_sets/util.ts | 5 +- 3 files changed, 31 insertions(+), 106 deletions(-) create mode 100644 changelogs/fragments/6948.yml diff --git a/changelogs/fragments/6948.yml b/changelogs/fragments/6948.yml new file mode 100644 index 000000000000..8b76f5e39105 --- /dev/null +++ b/changelogs/fragments/6948.yml @@ -0,0 +1,2 @@ +fix: +- Fix web log sample visualization & vis-builder not rendering with data source issue ([#6948](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6948)) \ No newline at end of file diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts index d2699128abd5..21167a761aea 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts @@ -398,7 +398,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Line) Avg bytes over time', uiStateJSON: '{}', @@ -408,13 +408,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '39b5bd70-eb7b-11ed-8e00-17d7d50cd7b2', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzE2LDFd', @@ -525,7 +519,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Area) Stacked extensions over time', uiStateJSON: '{}', @@ -535,13 +529,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'c0ba29f0-eb8f-11ed-8e00-17d7d50cd7b2', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzIyLDFd', @@ -652,7 +640,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Vertical Bar) Stacked responses over time', uiStateJSON: '{}', @@ -662,13 +650,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '23a5de70-eb99-11ed-8e00-17d7d50cd7b2', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzI4LDFd', @@ -780,7 +762,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Horizontal Bar) Top destination count', uiStateJSON: '{}', @@ -790,13 +772,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '08741f50-2275-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzM0LDFd', @@ -889,7 +865,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Heatmap) Source vs OS', uiStateJSON: '{}', @@ -899,13 +875,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '3d034700-227f-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzM5LDFd', @@ -953,7 +923,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Table) Bytes by request stats summary', uiStateJSON: '{"vis":{"sortColumn":{"colIndex":0,"direction":"asc"}}}', @@ -963,13 +933,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'f8df8de0-22a6-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzQyLDFd', @@ -1061,7 +1025,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Metric) Unique visitors', uiStateJSON: '{}', @@ -1071,13 +1035,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '104396f0-22a4-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzQ3LDFd', @@ -1170,7 +1128,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Pie) Visitors by OS', uiStateJSON: '{}', @@ -1180,13 +1138,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '7fd12620-2a44-11ee-92de-ad1b6a4928e5', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzUyLDFd', @@ -1234,7 +1186,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Gauge) Average bytes by extension', uiStateJSON: '{}', @@ -1244,13 +1196,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'f772de50-2281-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzU1LDFd', @@ -1298,7 +1244,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Goal) Average machine RAM', uiStateJSON: '{}', @@ -1308,13 +1254,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '9b0ae760-2282-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzU4LDFd', @@ -1362,7 +1302,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Coordinate Map) Geohash coordinates', uiStateJSON: '{"mapZoom":3,"mapCenter":[35.0659731379842,-107.80640422373408]}', @@ -1372,13 +1312,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'fe07f770-227f-11ee-b88b-47a93b5c527c', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzYxLDFd', @@ -1388,7 +1322,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Region Map) Destination count', uiStateJSON: '{}', @@ -1398,13 +1332,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: 'eb268650-2a43-11ee-92de-ad1b6a4928e5', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzYyLDFd', @@ -1490,7 +1418,7 @@ export const getSavedObjects = (): SavedObject[] => [ description: '', kibanaSavedObjectMeta: { searchSourceJSON: - '{"query":{"query":"","language":"kuery"},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + '{"index":"90943e30-9a47-11e8-b64d-95841ca0b247","query":{"query":"","language":"kuery"},"filter":[]}', }, title: '(Tag Cloud) Requests', uiStateJSON: '{}', @@ -1500,13 +1428,7 @@ export const getSavedObjects = (): SavedObject[] => [ }, id: '81017350-2a45-11ee-92de-ad1b6a4928e5', migrationVersion: { visualization: '7.10.0' }, - references: [ - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: 'kibanaSavedObjectMeta.searchSourceJSON.index', - type: 'index-pattern', - }, - ], + references: [], type: 'visualization', updated_at: '2023-07-25T17:00:34.843Z', version: 'WzY3LDFd', diff --git a/src/plugins/home/server/services/sample_data/data_sets/util.ts b/src/plugins/home/server/services/sample_data/data_sets/util.ts index 871a9574b591..4b2cc8b56fa3 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/util.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/util.ts @@ -25,7 +25,7 @@ export const appendDataSourceId = (id: string) => { const overrideSavedObjectId = (savedObject: SavedObject, idGenerator: (id: string) => string) => { savedObject.id = idGenerator(savedObject.id); // update reference - if (savedObject.type === 'dashboard') { + if (savedObject.type === 'dashboard' || savedObject.type === 'visualization-visbuilder') { savedObject.references.map((reference) => { if (reference.id) { reference.id = idGenerator(reference.id); @@ -88,7 +88,8 @@ export const getSavedObjectsWithDataSource = ( if ( saveObject.type === 'dashboard' || saveObject.type === 'visualization' || - saveObject.type === 'search' + saveObject.type === 'search' || + saveObject.type === 'visualization-visbuilder' ) { saveObject.attributes.title = saveObject.attributes.title + `_${dataSourceTitle}`; } From 4b9dd6795112b5c219a6d6676dd546cb0717e44a Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:52:01 -0700 Subject: [PATCH 011/276] [Data Explorer] Allow render from View directly, not from Data Explorer (#6167) (#6959) * [Discover] Remove double render This PR avoids re-rendering the entire AppContainer when data services update. The re-render is caused by history object which is in AppMountParameters. This history object is part of the application's routing context and can change frequently as the url is updated by query, filter or time range. Each change in the history object could potentially trigger a re-render of the AppContainer and its child components. With this PR, the AppContainer will not be re-loaded. Instead each component, like Canvas and Panel, will be updated. --------- (cherry picked from commit b7922427566e2b4bfdc4143407583bee95af4891) Signed-off-by: Anan Zhuang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../data_explorer/public/components/app.tsx | 24 +---- .../public/components/app_container.tsx | 93 ++++++++++--------- .../public/utils/use/shallow_equal.test.ts | 48 ++++++++++ .../public/utils/use/shallow_equal.ts | 22 +++++ .../view_components/utils/use_search.ts | 22 ++++- 5 files changed, 143 insertions(+), 66 deletions(-) create mode 100644 src/plugins/data_explorer/public/utils/use/shallow_equal.test.ts create mode 100644 src/plugins/data_explorer/public/utils/use/shallow_equal.ts diff --git a/src/plugins/data_explorer/public/components/app.tsx b/src/plugins/data_explorer/public/components/app.tsx index ff6b5931a404..6b19413d17e3 100644 --- a/src/plugins/data_explorer/public/components/app.tsx +++ b/src/plugins/data_explorer/public/components/app.tsx @@ -3,34 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; +import React from 'react'; import { AppMountParameters } from '../../../../core/public'; import { useView } from '../utils/use'; import { AppContainer } from './app_container'; -import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; -import { DataExplorerServices } from '../types'; -import { syncQueryStateWithUrl } from '../../../data/public'; export const DataExplorerApp = ({ params }: { params: AppMountParameters }) => { const { view } = useView(); - const { - services: { - data: { query }, - osdUrlStateStorage, - }, - } = useOpenSearchDashboards(); - const { pathname } = useLocation(); - - useEffect(() => { - // syncs `_g` portion of url with query services - const { stop } = syncQueryStateWithUrl(query, osdUrlStateStorage); - - return () => stop(); - - // this effect should re-run when pathname is changed to preserve querystring part, - // so the global state is always preserved - }, [query, osdUrlStateStorage, pathname]); - return ; }; diff --git a/src/plugins/data_explorer/public/components/app_container.tsx b/src/plugins/data_explorer/public/components/app_container.tsx index 529829140057..bf4a02bd223b 100644 --- a/src/plugins/data_explorer/public/components/app_container.tsx +++ b/src/plugins/data_explorer/public/components/app_container.tsx @@ -10,51 +10,60 @@ import { AppMountParameters } from '../../../../core/public'; import { Sidebar } from './sidebar'; import { NoView } from './no_view'; import { View } from '../services/view_service/view'; +import { shallowEqual } from '../utils/use/shallow_equal'; import './app_container.scss'; -export const AppContainer = ({ view, params }: { view?: View; params: AppMountParameters }) => { - const isMobile = useIsWithinBreakpoints(['xs', 's', 'm']); - // TODO: Make this more robust. - if (!view) { - return ; - } +export const AppContainer = React.memo( + ({ view, params }: { view?: View; params: AppMountParameters }) => { + const isMobile = useIsWithinBreakpoints(['xs', 's', 'm']); + // TODO: Make this more robust. + if (!view) { + return ; + } - const { Canvas, Panel, Context } = view; + const { Canvas, Panel, Context } = view; - const MemoizedPanel = memo(Panel); - const MemoizedCanvas = memo(Canvas); + const MemoizedPanel = memo(Panel); + const MemoizedCanvas = memo(Canvas); - // Render the application DOM. - return ( - - {/* TODO: improve fallback state */} - Loading...}> - - - {(EuiResizablePanel, EuiResizableButton) => ( - <> - - - - - - + // Render the application DOM. + return ( + + {/* TODO: improve fallback state */} + Loading...}> + + + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + + + + + - - - - - - - )} - - - - - ); -}; + + + + + + + )} + + + + + ); + }, + (prevProps, nextProps) => { + return ( + prevProps.view === nextProps.view && + shallowEqual(prevProps.params, nextProps.params, ['history']) + ); + } +); diff --git a/src/plugins/data_explorer/public/utils/use/shallow_equal.test.ts b/src/plugins/data_explorer/public/utils/use/shallow_equal.test.ts new file mode 100644 index 000000000000..d30bb2ffd3db --- /dev/null +++ b/src/plugins/data_explorer/public/utils/use/shallow_equal.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { shallowEqual } from './shallow_equal'; + +describe('shallowEqual', () => { + it('should return true for equal objects without ignored keys', () => { + const obj1 = { a: 1, b: 2, c: 3 }; + const obj2 = { a: 1, b: 2, c: 3 }; + const ignoreKeys = []; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(true); + }); + + it('should return false for objects with different values', () => { + const obj1 = { a: 1, b: 2, c: 3 }; + const obj2 = { a: 1, b: 2, c: 4 }; + const ignoreKeys = []; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(false); + }); + + it('should return false for objects with different keys', () => { + const obj1 = { a: 1, b: 2 }; + const obj2 = { a: 1, b: 2, c: 3 }; + const ignoreKeys = []; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(false); + }); + + it('should return true for objects with different values but ignored', () => { + const obj1 = { a: 1, b: 2, c: 3 }; + const obj2 = { a: 1, b: 2, c: 4 }; + const ignoreKeys = ['c']; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(true); + }); + + it('should return true for objects with different keys but ignored', () => { + const obj1 = { a: 1, b: 2 }; + const obj2 = { a: 1, b: 2, c: 4 }; + const ignoreKeys = ['c']; + + expect(shallowEqual(obj1, obj2, ignoreKeys)).toBe(true); + }); +}); diff --git a/src/plugins/data_explorer/public/utils/use/shallow_equal.ts b/src/plugins/data_explorer/public/utils/use/shallow_equal.ts new file mode 100644 index 000000000000..734d5b5cf64c --- /dev/null +++ b/src/plugins/data_explorer/public/utils/use/shallow_equal.ts @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// A simple shallow equal function that can ignore specified keys +export function shallowEqual(object1: any, object2: any, ignoreKeys: any) { + const keys1 = Object.keys(object1).filter((key) => !ignoreKeys.includes(key)); + const keys2 = Object.keys(object2).filter((key) => !ignoreKeys.includes(key)); + + if (keys1.length !== keys2.length) { + return false; + } + + for (const key of keys1) { + if (object1[key] !== object2[key]) { + return false; + } + } + + return true; +} diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index 9da9704f32a7..e3a84ae84638 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -9,6 +9,7 @@ import { debounceTime } from 'rxjs/operators'; import { i18n } from '@osd/i18n'; import { useEffect } from 'react'; import { cloneDeep } from 'lodash'; +import { useLocation } from 'react-router-dom'; import { RequestAdapter } from '../../../../../inspector/public'; import { DiscoverViewServices } from '../../../build_services'; import { search } from '../../../../../data/public'; @@ -31,6 +32,7 @@ import { getResponseInspectorStats, } from '../../../opensearch_dashboards_services'; import { SEARCH_ON_PAGE_LOAD_SETTING } from '../../../../common'; +import { syncQueryStateWithUrl } from '../../../../../data/public'; export enum ResultStatus { UNINITIALIZED = 'uninitialized', @@ -68,11 +70,19 @@ export type RefetchSubject = Subject; * }, [data$]); */ export const useSearch = (services: DiscoverViewServices) => { + const { pathname } = useLocation(); const initalSearchComplete = useRef(false); const [savedSearch, setSavedSearch] = useState(undefined); const { savedSearch: savedSearchId, sort, interval } = useSelector((state) => state.discover); - const { data, filterManager, getSavedSearchById, core, toastNotifications, chrome } = services; const indexPattern = useIndexPattern(services); + const { + data, + filterManager, + getSavedSearchById, + core, + toastNotifications, + osdUrlStateStorage, + } = services; const timefilter = data.query.timefilter.timefilter; const fetchStateRef = useRef<{ abortController: AbortController | undefined; @@ -309,6 +319,16 @@ export const useSearch = (services: DiscoverViewServices) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [getSavedSearchById, savedSearchId]); + useEffect(() => { + // syncs `_g` portion of url with query services + const { stop } = syncQueryStateWithUrl(data.query, osdUrlStateStorage); + + return () => stop(); + + // this effect should re-run when pathname is changed to preserve querystring part, + // so the global state is always preserved + }, [data.query, osdUrlStateStorage, pathname]); + return { data$, refetch$, From 642e4d37fa3f7ecfd7c14b11ff227d9d0bd4b502 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:15:47 +0800 Subject: [PATCH 012/276] [Workspace]Change workspace description field to textarea (#6907) (#6960) * Change workspace description field to textarea * Changeset file for PR #6907 created/updated * Update description UI --------- (cherry picked from commit fe443e9408263518efacd5b6eda64afe26ae5b8b) Signed-off-by: Lin Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: Lu Yu --- changelogs/fragments/6907.yml | 2 ++ .../workspace_creator.test.tsx | 17 ---------- .../workspace_form/use_workspace_form.test.ts | 16 ---------- .../workspace_form/use_workspace_form.ts | 11 +++++-- .../components/workspace_form/utils.test.ts | 5 --- .../public/components/workspace_form/utils.ts | 5 --- .../workspace_form/workspace_form.tsx | 32 +++++++++++++------ .../workspace_updater.test.tsx | 17 ---------- 8 files changed, 32 insertions(+), 73 deletions(-) create mode 100644 changelogs/fragments/6907.yml diff --git a/changelogs/fragments/6907.yml b/changelogs/fragments/6907.yml new file mode 100644 index 000000000000..6d6e804bfc30 --- /dev/null +++ b/changelogs/fragments/6907.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace] Change description field to textarea ([#6907](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6907)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx index 1682e24c3025..06d766a831e1 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx @@ -116,23 +116,6 @@ describe('WorkspaceCreator', () => { expect(workspaceClientCreate).not.toHaveBeenCalled(); }); - it('should not create workspace with invalid description', async () => { - const { getByTestId } = render( - - ); - const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); - fireEvent.input(nameInput, { - target: { value: 'test workspace name' }, - }); - const descriptionInput = getByTestId('workspaceForm-workspaceDetails-descriptionInputText'); - fireEvent.input(descriptionInput, { - target: { value: '~' }, - }); - expect(workspaceClientCreate).not.toHaveBeenCalled(); - }); - it('cancel create workspace', async () => { const { findByText, getByTestId } = render( { }); expect(onSubmitMock).not.toHaveBeenCalled(); }); - it('should return "Invalid workspace description" and not call onSubmit when invalid description', async () => { - const { renderResult, onSubmitMock } = setup({ - id: 'foo', - name: 'test-workspace-name', - description: '~', - }); - expect(renderResult.result.current.formErrors).toEqual({}); - - act(() => { - renderResult.result.current.handleFormSubmit({ preventDefault: jest.fn() }); - }); - expect(renderResult.result.current.formErrors).toEqual({ - description: 'Invalid workspace description', - }); - expect(onSubmitMock).not.toHaveBeenCalled(); - }); it('should call onSubmit with workspace name and features', async () => { const { renderResult, onSubmitMock } = setup({ id: 'foo', diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts index cded7c4bcb71..07de89ffe18a 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts @@ -4,7 +4,12 @@ */ import { useCallback, useState, FormEventHandler, useRef, useMemo, useEffect } from 'react'; -import { htmlIdGenerator, EuiFieldTextProps, EuiColorPickerProps } from '@elastic/eui'; +import { + htmlIdGenerator, + EuiFieldTextProps, + EuiColorPickerProps, + EuiTextAreaProps, +} from '@elastic/eui'; import { useApplications } from '../../hooks'; import { featureMatchesConfig } from '../../utils'; @@ -97,7 +102,7 @@ export const useWorkspaceForm = ({ application, defaultValues, onSubmit }: Works setName(e.target.value); }, []); - const handleDescriptionInputChange = useCallback['onChange']>((e) => { + const handleDescriptionChange = useCallback['onChange']>((e) => { setDescription(e.target.value); }, []); @@ -136,6 +141,6 @@ export const useWorkspaceForm = ({ application, defaultValues, onSubmit }: Works handleTabFeatureClick, setPermissionSettings, handleTabPermissionClick, - handleDescriptionInputChange, + handleDescriptionChange, }; }; diff --git a/src/plugins/workspace/public/components/workspace_form/utils.test.ts b/src/plugins/workspace/public/components/workspace_form/utils.test.ts index c2cf46fcf292..ec078c8a0456 100644 --- a/src/plugins/workspace/public/components/workspace_form/utils.test.ts +++ b/src/plugins/workspace/public/components/workspace_form/utils.test.ts @@ -250,11 +250,6 @@ describe('validateWorkspaceForm', () => { it('should return error if name is invalid', () => { expect(validateWorkspaceForm({ name: '~' }).name).toEqual('Invalid workspace name'); }); - it('should return error if description is invalid', () => { - expect(validateWorkspaceForm({ description: '~' }).description).toEqual( - 'Invalid workspace description' - ); - }); it('should return error if permission setting type is invalid', () => { expect( validateWorkspaceForm({ diff --git a/src/plugins/workspace/public/components/workspace_form/utils.ts b/src/plugins/workspace/public/components/workspace_form/utils.ts index 404314cc652a..f5a7bd149218 100644 --- a/src/plugins/workspace/public/components/workspace_form/utils.ts +++ b/src/plugins/workspace/public/components/workspace_form/utils.ts @@ -255,11 +255,6 @@ export const validateWorkspaceForm = ( defaultMessage: "Name can't be empty.", }); } - if (description && !isValidFormTextInput(description)) { - formErrors.description = i18n.translate('workspace.form.detail.description.invalid', { - defaultMessage: 'Invalid workspace description', - }); - } if (permissionSettings) { const permissionSettingsErrors: { [key: number]: string } = {}; for (let i = 0; i < permissionSettings.length; i++) { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index de841b09c60e..794f983bd989 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -16,6 +16,7 @@ import { EuiHorizontalRule, EuiTab, EuiTabs, + EuiTextArea, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; @@ -47,7 +48,7 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { handleTabFeatureClick, setPermissionSettings, handleTabPermissionClick, - handleDescriptionInputChange, + handleDescriptionChange, } = useWorkspaceForm(props); const workspaceDetailsTitle = i18n.translate('workspace.form.workspaceDetails.title', { defaultMessage: 'Workspace Details', @@ -91,18 +92,29 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { Description - optional } - helpText={i18n.translate('workspace.form.workspaceDetails.description.helpText', { - defaultMessage: - 'Valid characters are a-z, A-Z, 0-9, (), [], _ (underscore), - (hyphen) and (space).', - })} isInvalid={!!formErrors.description} error={formErrors.description} > - + <> + + {i18n.translate('workspace.form.workspaceDetails.description.introduction', { + defaultMessage: + 'Help others understand the purpose of this workspace by providing an overview of the workspace you’re creating.', + })} + + + { expect(workspaceClientUpdate).not.toHaveBeenCalled(); }); - it('cannot update workspace with invalid description', async () => { - const { getByTestId } = render( - - ); - const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); - fireEvent.input(nameInput, { - target: { value: 'test workspace name' }, - }); - const descriptionInput = getByTestId('workspaceForm-workspaceDetails-descriptionInputText'); - fireEvent.input(descriptionInput, { - target: { value: '~' }, - }); - expect(workspaceClientUpdate).not.toHaveBeenCalled(); - }); - it('cancel update workspace', async () => { const { findByText, getByTestId } = render( Date: Fri, 7 Jun 2024 09:47:31 -0700 Subject: [PATCH 013/276] [Workspace]Feat add use cases to workspace form (#6887) (#6967) * Add workspace use case to workspace form * Remove feature selector in workspace form * Show use cases in workspace list page * Change direction for workspace use case selector * Modify test cases for match use case * Make use cases as a required field * Update ui according feedbacks * Add management feature to dashboards and visualize use cases * Update latest feature relationships * Changeset file for PR #6887 created/updated * Changeset file for PR #6887 created/updated * Update test case for workspace creator and updater * Address unit test * Add discover feature to all use case * Add missing features to security analytics * Address PR comments * Add comment for workspace use cases map * Update use case UI * Remove the permissions tab * Update breadcrum to Create a workspace * Address ut failed --------- (cherry picked from commit 7be3e3090d7ae702dbfa61ef140f1d6a6b1c9f0f) Signed-off-by: Lin Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: Yulong Ruan --- changelogs/fragments/6887.yml | 2 + src/plugins/workspace/common/constants.ts | 103 +++++++++++++ .../workspace_creator.test.tsx | 66 ++++---- .../workspace_creator/workspace_creator.tsx | 2 +- .../components/workspace_creator_app.tsx | 2 +- .../components/workspace_form/constants.ts | 6 - .../public/components/workspace_form/types.ts | 10 -- .../workspace_form/use_workspace_form.test.ts | 26 +++- .../workspace_form/use_workspace_form.ts | 91 +++++------ .../components/workspace_form/utils.test.ts | 96 +----------- .../public/components/workspace_form/utils.ts | 73 ++------- .../workspace_feature_selector.test.tsx | 100 ------------ .../workspace_feature_selector.tsx | 142 ------------------ .../workspace_form/workspace_form.tsx | 81 ++++------ .../workspace_form/workspace_use_case.scss | 8 + .../workspace_use_case.test.tsx | 55 +++++++ .../workspace_form/workspace_use_case.tsx | 99 ++++++++++++ .../__snapshots__/index.test.tsx.snap | 4 +- .../components/workspace_list/index.test.tsx | 3 +- .../components/workspace_list/index.tsx | 18 ++- .../workspace_overview.test.tsx | 2 +- .../workspace_updater.test.tsx | 16 +- src/plugins/workspace/public/plugin.ts | 2 +- src/plugins/workspace/public/utils.test.ts | 15 ++ src/plugins/workspace/public/utils.ts | 39 ++++- 25 files changed, 484 insertions(+), 577 deletions(-) create mode 100644 changelogs/fragments/6887.yml delete mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.test.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.tsx create mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_use_case.scss create mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx create mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx diff --git a/changelogs/fragments/6887.yml b/changelogs/fragments/6887.yml new file mode 100644 index 000000000000..b98591b0aa4c --- /dev/null +++ b/changelogs/fragments/6887.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace]Add use cases to workspace form ([#6887](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6887)) \ No newline at end of file diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index 17a8291b4f72..4380ce40a10b 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -79,3 +79,106 @@ export const WORKSPACE_APP_CATEGORIES: Record = Object.free order: 14000, }, }); +/** + * + * This is a temp solution to store relationships between use cases and features. + * The relationship should be provided by plugin itself. The workspace plugin should + * provide some method to register single feature to the use case map instead of + * store a static map in workspace. + * + */ +export const WORKSPACE_USE_CASES = Object.freeze({ + observability: { + id: 'observability', + title: i18n.translate('workspace.usecase.observability.title', { + defaultMessage: 'Observability', + }), + description: i18n.translate('workspace.usecase.observability.description', { + defaultMessage: + 'Gain visibility into system health, performance, and reliability through monitoring and analysis of logs, metrics, and traces.', + }), + features: [ + 'discover', + 'dashboards', + 'visualize', + 'maps-dashboards', + 'observability-notebooks', + 'reports-dashboards', + 'integrations', + 'alerting', + 'anomaly-detection-dashboards', + 'observability-metrics', + 'observability-traces', + 'observability-applications', + // Add management avoid index patterns application not found for dashboards or visualize + 'management', + ] as string[], + }, + 'security-analytics': { + id: 'security-analytics', + title: i18n.translate('workspace.usecase.security.analytics.title', { + defaultMessage: 'Security Analytics', + }), + description: i18n.translate('workspace.usecase.analytics.description', { + defaultMessage: + 'Detect and investigate potential security threats and vulnerabilities across your systems and data.', + }), + features: [ + 'discover', + 'dashboards', + 'visualize', + 'maps-dashboards', + 'observability-notebooks', + 'reports-dashboards', + 'integrations', + 'alerting', + 'anomaly-detection-dashboards', + 'opensearch_security_analytics_dashboards', + // Add management avoid index patterns application not found for dashboards or visualize + 'management', + ] as string[], + }, + analytics: { + id: 'analytics', + title: i18n.translate('workspace.usecase.analytics.title', { + defaultMessage: 'Analytics', + }), + description: i18n.translate('workspace.usecase.analytics.description', { + defaultMessage: + 'Analyze data to derive insights, identify patterns and trends, and make data-driven decisions.', + }), + features: [ + 'discover', + 'dashboards', + 'visualize', + 'maps-dashboards', + 'observability-notebooks', + 'reports-dashboards', + 'integrations', + 'alerting', + 'anomaly-detection-dashboards', + // Add management avoid index patterns application not found for dashboards or visualize + 'management', + ] as string[], + }, + search: { + id: 'search', + title: i18n.translate('workspace.usecase.search.title', { + defaultMessage: 'Search', + }), + description: i18n.translate('workspace.usecase.search.description', { + defaultMessage: + "Quickly find and explore relevant information across your organization's data sources.", + }), + features: [ + 'discover', + 'dashboards', + 'visualize', + 'maps-dashboards', + 'reports-dashboards', + 'searchRelevance', + // Add management avoid index patterns application not found for dashboards or visualize + 'management', + ] as string[], + }, +}); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx index 06d766a831e1..1c1632f7cb4d 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx @@ -19,11 +19,8 @@ const navigateToApp = jest.fn(); const notificationToastsAddSuccess = jest.fn(); const notificationToastsAddDanger = jest.fn(); const PublicAPPInfoMap = new Map([ - ['app1', { id: 'app1', title: 'app1' }], - ['app2', { id: 'app2', title: 'app2', category: { id: 'category1', label: 'category1' } }], - ['app3', { id: 'app3', category: { id: 'category1', label: 'category1' } }], - ['app4', { id: 'app4', category: { id: 'category2', label: 'category2' } }], - ['app5', { id: 'app5', category: { id: 'category2', label: 'category2' } }], + ['data-explorer', { id: 'data-explorer', title: 'Data Explorer' }], + ['dashboards', { id: 'dashboards', title: 'Dashboards' }], ]); const mockCoreStart = coreMock.createStart(); @@ -116,6 +113,22 @@ describe('WorkspaceCreator', () => { expect(workspaceClientCreate).not.toHaveBeenCalled(); }); + it('should not create workspace without use cases', async () => { + setHrefSpy.mockReset(); + const { getByTestId } = render( + + ); + const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); + fireEvent.input(nameInput, { + target: { value: 'test workspace name' }, + }); + expect(setHrefSpy).not.toHaveBeenCalled(); + fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); + expect(workspaceClientCreate).not.toHaveBeenCalled(); + }); + it('cancel create workspace', async () => { const { findByText, getByTestId } = render( { fireEvent.input(colorSelector, { target: { value: '#000000' }, }); + fireEvent.click(getByTestId('workspaceUseCase-observability')); fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); expect(workspaceClientCreate).toHaveBeenCalledWith( expect.objectContaining({ name: 'test workspace name', color: '#000000', description: 'test workspace description', + features: expect.arrayContaining(['use-case-observability']), }), undefined ); @@ -163,37 +178,6 @@ describe('WorkspaceCreator', () => { expect(notificationToastsAddDanger).not.toHaveBeenCalled(); }); - it('create workspace with customized features', async () => { - setHrefSpy.mockReset(); - const { getByTestId } = render( - - ); - const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); - fireEvent.input(nameInput, { - target: { value: 'test workspace name' }, - }); - fireEvent.click(getByTestId('workspaceForm-workspaceFeatureVisibility-app1')); - fireEvent.click(getByTestId('workspaceForm-workspaceFeatureVisibility-category1')); - expect(setHrefSpy).not.toHaveBeenCalled(); - fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); - expect(workspaceClientCreate).toHaveBeenCalledWith( - expect.objectContaining({ - name: 'test workspace name', - features: expect.arrayContaining(['app1', 'app2', 'app3']), - }), - undefined - ); - await waitFor(() => { - expect(notificationToastsAddSuccess).toHaveBeenCalled(); - }); - expect(notificationToastsAddDanger).not.toHaveBeenCalled(); - await waitFor(() => { - expect(setHrefSpy).toHaveBeenCalledWith(expect.stringMatching(/workspace_overview$/)); - }); - }); - it('should show danger toasts after create workspace failed', async () => { workspaceClientCreate.mockReturnValueOnce({ result: { id: 'failResult' }, success: false }); const { getByTestId } = render( @@ -205,6 +189,7 @@ describe('WorkspaceCreator', () => { fireEvent.input(nameInput, { target: { value: 'test workspace name' }, }); + fireEvent.click(getByTestId('workspaceUseCase-observability')); fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); expect(workspaceClientCreate).toHaveBeenCalled(); await waitFor(() => { @@ -226,6 +211,7 @@ describe('WorkspaceCreator', () => { fireEvent.input(nameInput, { target: { value: 'test workspace name' }, }); + fireEvent.click(getByTestId('workspaceUseCase-observability')); fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); expect(workspaceClientCreate).toHaveBeenCalled(); await waitFor(() => { @@ -235,12 +221,16 @@ describe('WorkspaceCreator', () => { }); it('create workspace with customized permissions', async () => { - const { getByTestId, getByText, getAllByText } = render(); + const { getByTestId, getAllByText } = render( + + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, }); - fireEvent.click(getByText('Users & Permissions')); + fireEvent.click(getByTestId('workspaceUseCase-observability')); fireEvent.click(getByTestId('workspaceForm-permissionSettingPanel-user-addNew')); const userIdInput = getAllByText('Select')[0]; fireEvent.click(userIdInput); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx index 11d411f6e0d2..61905572f628 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx @@ -78,7 +78,7 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { return ( - + { chrome?.setBreadcrumbs([ { text: i18n.translate('workspace.workspaceCreateTitle', { - defaultMessage: 'Create workspace', + defaultMessage: 'Create a workspace', }), }, ]); diff --git a/src/plugins/workspace/public/components/workspace_form/constants.ts b/src/plugins/workspace/public/components/workspace_form/constants.ts index 693f0cdce141..073477b2ad89 100644 --- a/src/plugins/workspace/public/components/workspace_form/constants.ts +++ b/src/plugins/workspace/public/components/workspace_form/constants.ts @@ -11,12 +11,6 @@ export enum WorkspaceOperationType { Update = 'update', } -export enum WorkspaceFormTabs { - NotSelected, - FeatureVisibility, - UsersAndPermissions, -} - export enum WorkspacePermissionItemType { User = 'user', Group = 'group', diff --git a/src/plugins/workspace/public/components/workspace_form/types.ts b/src/plugins/workspace/public/components/workspace_form/types.ts index 33521cc8dcb9..d8679629c48b 100644 --- a/src/plugins/workspace/public/components/workspace_form/types.ts +++ b/src/plugins/workspace/public/components/workspace_form/types.ts @@ -34,16 +34,6 @@ export interface WorkspaceFormData extends WorkspaceFormSubmitData { reserved?: boolean; } -export interface WorkspaceFeature { - id: string; - name: string; -} - -export interface WorkspaceFeatureGroup { - name: string; - features: WorkspaceFeature[]; -} - export type WorkspaceFormErrors = { [key in keyof Omit]?: string; } & { diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts index 5b756348e795..9e67d49bd07d 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts @@ -35,15 +35,35 @@ describe('useWorkspaceForm', () => { act(() => { renderResult.result.current.handleFormSubmit({ preventDefault: jest.fn() }); }); - expect(renderResult.result.current.formErrors).toEqual({ - name: 'Invalid workspace name', + expect(renderResult.result.current.formErrors).toEqual( + expect.objectContaining({ + name: 'Invalid workspace name', + }) + ); + expect(onSubmitMock).not.toHaveBeenCalled(); + }); + it('should return "Use case is required. Select a use case." and not call onSubmit', async () => { + const { renderResult, onSubmitMock } = setup({ + id: 'foo', + name: 'test-workspace-name', }); + expect(renderResult.result.current.formErrors).toEqual({}); + + act(() => { + renderResult.result.current.handleFormSubmit({ preventDefault: jest.fn() }); + }); + expect(renderResult.result.current.formErrors).toEqual( + expect.objectContaining({ + features: 'Use case is required. Select a use case.', + }) + ); expect(onSubmitMock).not.toHaveBeenCalled(); }); it('should call onSubmit with workspace name and features', async () => { const { renderResult, onSubmitMock } = setup({ id: 'foo', name: 'test-workspace-name', + features: ['use-case-observability'], }); expect(renderResult.result.current.formErrors).toEqual({}); @@ -53,7 +73,7 @@ describe('useWorkspaceForm', () => { expect(onSubmitMock).toHaveBeenCalledWith( expect.objectContaining({ name: 'test-workspace-name', - features: ['workspace_update', 'workspace_overview'], + features: ['use-case-observability', 'workspace_update', 'workspace_overview'], }) ); }); diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts index 07de89ffe18a..4536e56d21bd 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts @@ -3,42 +3,40 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { useCallback, useState, FormEventHandler, useRef, useMemo, useEffect } from 'react'; +import { useCallback, useState, FormEventHandler, useRef, useMemo } from 'react'; import { htmlIdGenerator, EuiFieldTextProps, EuiColorPickerProps, EuiTextAreaProps, } from '@elastic/eui'; + import { useApplications } from '../../hooks'; -import { featureMatchesConfig } from '../../utils'; +import { + getUseCaseFeatureConfig, + getUseCaseFromFeatureConfig, + isUseCaseFeatureConfig, +} from '../../utils'; -import { WorkspaceFormTabs } from './constants'; import { WorkspaceFormProps, WorkspaceFormErrors, WorkspacePermissionSetting } from './types'; import { appendDefaultFeatureIds, getNumberOfErrors, validateWorkspaceForm } from './utils'; const workspaceHtmlIdGenerator = htmlIdGenerator(); +const isNotNull = (value: T | null): value is T => !!value; + export const useWorkspaceForm = ({ application, defaultValues, onSubmit }: WorkspaceFormProps) => { const applications = useApplications(application); const [name, setName] = useState(defaultValues?.name); const [description, setDescription] = useState(defaultValues?.description); const [color, setColor] = useState(defaultValues?.color); - const [selectedTab, setSelectedTab] = useState(WorkspaceFormTabs.FeatureVisibility); - // The matched feature id list based on original feature config, - // the feature category will be expanded to list of feature ids - const defaultFeatures = useMemo(() => { - // The original feature list, may contain feature id and category wildcard like @management, etc. - const defaultOriginalFeatures = defaultValues?.features ?? []; - return applications.filter(featureMatchesConfig(defaultOriginalFeatures)).map((app) => app.id); - }, [defaultValues?.features, applications]); - - const defaultFeaturesRef = useRef(defaultFeatures); - defaultFeaturesRef.current = defaultFeatures; - - const [selectedFeatureIds, setSelectedFeatureIds] = useState( - appendDefaultFeatureIds(defaultFeatures) + const [featureConfigs, setFeatureConfigs] = useState( + appendDefaultFeatureIds(defaultValues?.features ?? []) + ); + const selectedUseCases = useMemo( + () => featureConfigs.map(getUseCaseFromFeatureConfig).filter(isNotNull), + [featureConfigs] ); const [permissionSettings, setPermissionSettings] = useState< Array & Partial> @@ -54,7 +52,8 @@ export const useWorkspaceForm = ({ application, defaultValues, onSubmit }: Works const getFormData = () => ({ name, description, - features: selectedFeatureIds, + features: featureConfigs, + useCases: selectedUseCases, color, permissionSettings, }); @@ -65,6 +64,20 @@ export const useWorkspaceForm = ({ application, defaultValues, onSubmit }: Works formIdRef.current = workspaceHtmlIdGenerator(); } + const handleUseCasesChange = useCallback( + (newUseCases: string[]) => { + setFeatureConfigs((previousFeatureConfigs) => { + return [ + ...previousFeatureConfigs.filter( + (featureConfig) => !isUseCaseFeatureConfig(featureConfig) + ), + ...newUseCases.map((useCaseItem) => getUseCaseFeatureConfig(useCaseItem)), + ]; + }); + }, + [setFeatureConfigs] + ); + const handleFormSubmit = useCallback( (e) => { e.preventDefault(); @@ -75,27 +88,15 @@ export const useWorkspaceForm = ({ application, defaultValues, onSubmit }: Works return; } - const featureConfigChanged = - formData.features.length !== defaultFeatures.length || - formData.features.some((feat) => !defaultFeatures.includes(feat)); - - if (!featureConfigChanged) { - // If feature config not changed, set workspace feature config to the original value. - // The reason why we do this is when a workspace feature is configured by wildcard, - // such as `['@management']` or `['*']`. The form value `formData.features` will be - // expanded to array of individual feature id, if the feature hasn't changed, we will - // set the feature config back to the original value so that category wildcard won't - // expanded to feature ids - formData.features = defaultValues?.features ?? []; - } - onSubmit?.({ - ...formData, name: formData.name!, + description: formData.description, + features: formData.features, + color: formData.color, permissionSettings: formData.permissionSettings as WorkspacePermissionSetting[], }); }, - [defaultFeatures, onSubmit, defaultValues?.features] + [onSubmit] ); const handleNameInputChange = useCallback['onChange']>((e) => { @@ -110,37 +111,17 @@ export const useWorkspaceForm = ({ application, defaultValues, onSubmit }: Works setColor(text); }, []); - const handleTabFeatureClick = useCallback(() => { - setSelectedTab(WorkspaceFormTabs.FeatureVisibility); - }, []); - - const handleTabPermissionClick = useCallback(() => { - setSelectedTab(WorkspaceFormTabs.UsersAndPermissions); - }, []); - - const handleFeaturesChange = useCallback((featureIds: string[]) => { - setSelectedFeatureIds(featureIds); - }, []); - - useEffect(() => { - // When applications changed, reset form feature selection to original value - setSelectedFeatureIds(appendDefaultFeatureIds(defaultFeaturesRef.current)); - }, [applications]); - return { formId: formIdRef.current, formData: getFormData(), formErrors, - selectedTab, applications, numberOfErrors, handleFormSubmit, handleColorChange, - handleFeaturesChange, + handleUseCasesChange, handleNameInputChange, - handleTabFeatureClick, setPermissionSettings, - handleTabPermissionClick, handleDescriptionChange, }; }; diff --git a/src/plugins/workspace/public/components/workspace_form/utils.test.ts b/src/plugins/workspace/public/components/workspace_form/utils.test.ts index ec078c8a0456..6935f84eda35 100644 --- a/src/plugins/workspace/public/components/workspace_form/utils.test.ts +++ b/src/plugins/workspace/public/components/workspace_form/utils.test.ts @@ -3,106 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { AppNavLinkStatus, DEFAULT_APP_CATEGORIES } from '../../../../../core/public'; import { validateWorkspaceForm, - convertApplicationsToFeaturesOrGroups, convertPermissionSettingsToPermissions, convertPermissionsToPermissionSettings, } from './utils'; import { WorkspacePermissionMode } from '../../../common/constants'; import { WorkspacePermissionItemType } from './constants'; -describe('convertApplicationsToFeaturesOrGroups', () => { - it('should group same category applications in same feature group', () => { - expect( - convertApplicationsToFeaturesOrGroups([ - { - id: 'foo', - title: 'Foo', - navLinkStatus: AppNavLinkStatus.visible, - category: DEFAULT_APP_CATEGORIES.opensearchDashboards, - }, - { - id: 'bar', - title: 'Bar', - navLinkStatus: AppNavLinkStatus.visible, - category: DEFAULT_APP_CATEGORIES.opensearchDashboards, - }, - { - id: 'baz', - title: 'Baz', - navLinkStatus: AppNavLinkStatus.visible, - category: DEFAULT_APP_CATEGORIES.observability, - }, - ]) - ).toEqual([ - { - name: 'OpenSearch Dashboards', - features: [ - { - id: 'foo', - name: 'Foo', - }, - { - id: 'bar', - name: 'Bar', - }, - ], - }, - { - name: 'Observability', - features: [ - { - id: 'baz', - name: 'Baz', - }, - ], - }, - ]); - }); - it('should return features if application without category', () => { - expect( - convertApplicationsToFeaturesOrGroups([ - { - id: 'foo', - title: 'Foo', - navLinkStatus: AppNavLinkStatus.visible, - }, - { - id: 'baz', - title: 'Baz', - navLinkStatus: AppNavLinkStatus.visible, - category: DEFAULT_APP_CATEGORIES.observability, - }, - { - id: 'bar', - title: 'Bar', - navLinkStatus: AppNavLinkStatus.visible, - }, - ]) - ).toEqual([ - { - id: 'foo', - name: 'Foo', - }, - { - id: 'bar', - name: 'Bar', - }, - { - name: 'Observability', - features: [ - { - id: 'baz', - name: 'Baz', - }, - ], - }, - ]); - }); -}); - describe('convertPermissionSettingsToPermissions', () => { it('should return undefined if permission items not provided', () => { expect(convertPermissionSettingsToPermissions(undefined)).toBeUndefined(); @@ -250,6 +158,9 @@ describe('validateWorkspaceForm', () => { it('should return error if name is invalid', () => { expect(validateWorkspaceForm({ name: '~' }).name).toEqual('Invalid workspace name'); }); + it('should return error if use case is empty', () => { + expect(validateWorkspaceForm({}).features).toEqual('Use case is required. Select a use case.'); + }); it('should return error if permission setting type is invalid', () => { expect( validateWorkspaceForm({ @@ -350,6 +261,7 @@ describe('validateWorkspaceForm', () => { group: 'foo', }, ], + features: ['use-case-observability'], }) ).toEqual({}); }); diff --git a/src/plugins/workspace/public/components/workspace_form/utils.ts b/src/plugins/workspace/public/components/workspace_form/utils.ts index f5a7bd149218..352cbe1aca1a 100644 --- a/src/plugins/workspace/public/components/workspace_form/utils.ts +++ b/src/plugins/workspace/public/components/workspace_form/utils.ts @@ -5,26 +5,16 @@ import { i18n } from '@osd/i18n'; -import { PublicAppInfo } from '../../../../../core/public'; import type { SavedObjectPermissions } from '../../../../../core/types'; import { DEFAULT_SELECTED_FEATURES_IDS, WorkspacePermissionMode } from '../../../common/constants'; +import { isUseCaseFeatureConfig } from '../../utils'; import { optionIdToWorkspacePermissionModesMap, PermissionModeId, WorkspacePermissionItemType, } from './constants'; -import { - WorkspaceFeature, - WorkspaceFeatureGroup, - WorkspaceFormErrors, - WorkspaceFormSubmitData, - WorkspacePermissionSetting, -} from './types'; - -export const isWorkspaceFeatureGroup = ( - featureOrGroup: WorkspaceFeature | WorkspaceFeatureGroup -): featureOrGroup is WorkspaceFeatureGroup => 'features' in featureOrGroup; +import { WorkspaceFormErrors, WorkspaceFormSubmitData, WorkspacePermissionSetting } from './types'; export const appendDefaultFeatureIds = (ids: string[]) => { // concat default checked ids and unique the result @@ -51,58 +41,12 @@ export const getNumberOfErrors = (formErrors: WorkspaceFormErrors) => { if (formErrors.permissionSettings) { numberOfErrors += Object.keys(formErrors.permissionSettings).length; } + if (formErrors.features) { + numberOfErrors += 1; + } return numberOfErrors; }; -export const convertApplicationsToFeaturesOrGroups = ( - applications: Array< - Pick - > -) => { - const UNDEFINED = 'undefined'; - - /** - * - * Convert applications to features map, the map use category label as - * map key and group all same category applications in one array after - * transfer application to feature. - * - **/ - const categoryLabel2Features = applications.reduce<{ - [key: string]: WorkspaceFeature[]; - }>((previousValue, application) => { - const label = application.category?.label || UNDEFINED; - - return { - ...previousValue, - [label]: [...(previousValue[label] || []), { id: application.id, name: application.title }], - }; - }, {}); - - /** - * - * Iterate all keys of categoryLabel2Features map, convert map to features or groups array. - * Features with category label will be converted to feature groups. Features without "undefined" - * category label will be converted to single features. Then append them to the result array. - * - **/ - return Object.keys(categoryLabel2Features).reduce< - Array - >((previousValue, categoryLabel) => { - const features = categoryLabel2Features[categoryLabel]; - if (categoryLabel === UNDEFINED) { - return [...previousValue, ...features]; - } - return [ - ...previousValue, - { - name: categoryLabel, - features, - }, - ]; - }, []); -}; - export const isUserOrGroupPermissionSettingDuplicated = ( permissionSettings: Array>, permissionSettingToCheck: WorkspacePermissionSetting @@ -243,7 +187,7 @@ export const validateWorkspaceForm = ( } ) => { const formErrors: WorkspaceFormErrors = {}; - const { name, description, permissionSettings } = formData; + const { name, permissionSettings, features } = formData; if (name) { if (!isValidFormTextInput(name)) { formErrors.name = i18n.translate('workspace.form.detail.name.invalid', { @@ -255,6 +199,11 @@ export const validateWorkspaceForm = ( defaultMessage: "Name can't be empty.", }); } + if (!features || !features.some((featureConfig) => isUseCaseFeatureConfig(featureConfig))) { + formErrors.features = i18n.translate('workspace.form.features.empty', { + defaultMessage: 'Use case is required. Select a use case.', + }); + } if (permissionSettings) { const permissionSettingsErrors: { [key: number]: string } = {}; for (let i = 0; i < permissionSettings.length; i++) { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.test.tsx deleted file mode 100644 index 313d459b6018..000000000000 --- a/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.test.tsx +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { fireEvent, render } from '@testing-library/react'; -import { - WorkspaceFeatureSelector, - WorkspaceFeatureSelectorProps, -} from './workspace_feature_selector'; -import { AppNavLinkStatus, AppStatus } from '../../../../../core/public'; - -const setup = (options?: Partial) => { - const onChangeMock = jest.fn(); - const applications = [ - { - id: 'app-1', - title: 'App 1', - category: { id: 'category-1', label: 'Category 1' }, - navLinkStatus: AppNavLinkStatus.visible, - status: AppStatus.accessible, - appRoute: '/app-1', - }, - { - id: 'app-2', - title: 'App 2', - category: { id: 'category-1', label: 'Category 1' }, - navLinkStatus: AppNavLinkStatus.visible, - status: AppStatus.accessible, - appRoute: '/app-2', - }, - { - id: 'app-3', - title: 'App 3', - category: { id: 'category-2', label: 'Category 2' }, - navLinkStatus: AppNavLinkStatus.visible, - status: AppStatus.accessible, - appRoute: '/app-3', - }, - { - id: 'app-4', - title: 'App 4', - navLinkStatus: AppNavLinkStatus.visible, - status: AppStatus.accessible, - appRoute: '/app-4', - }, - ]; - const renderResult = render( - - ); - return { - renderResult, - onChangeMock, - }; -}; - -describe('WorkspaceFeatureSelector', () => { - it('should call onChange with clicked feature', () => { - const { renderResult, onChangeMock } = setup(); - - expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getByText('App 1')); - expect(onChangeMock).toHaveBeenCalledWith(['app-1']); - }); - it('should call onChange with empty array after selected feature clicked', () => { - const { renderResult, onChangeMock } = setup({ - selectedFeatures: ['app-2'], - }); - - expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getByText('App 2')); - expect(onChangeMock).toHaveBeenCalledWith([]); - }); - it('should call onChange with features under clicked group', () => { - const { renderResult, onChangeMock } = setup(); - - expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click( - renderResult.getByTestId('workspaceForm-workspaceFeatureVisibility-Category 1') - ); - expect(onChangeMock).toHaveBeenCalledWith(['app-1', 'app-2']); - }); - it('should call onChange without features under clicked group when group already selected', () => { - const { renderResult, onChangeMock } = setup({ - selectedFeatures: ['app-1', 'app-2', 'app-3'], - }); - - expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click( - renderResult.getByTestId('workspaceForm-workspaceFeatureVisibility-Category 1') - ); - expect(onChangeMock).toHaveBeenCalledWith(['app-3']); - }); -}); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.tsx deleted file mode 100644 index 8c99e5fa6642..000000000000 --- a/src/plugins/workspace/public/components/workspace_form/workspace_feature_selector.tsx +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useCallback, useMemo } from 'react'; -import { - EuiText, - EuiFlexItem, - EuiCheckbox, - EuiCheckboxGroup, - EuiFlexGroup, - EuiCheckboxGroupProps, - EuiCheckboxProps, -} from '@elastic/eui'; - -import { PublicAppInfo } from '../../../../../core/public'; - -import { isWorkspaceFeatureGroup, convertApplicationsToFeaturesOrGroups } from './utils'; - -export interface WorkspaceFeatureSelectorProps { - selectedFeatures: string[]; - onChange: (newFeatures: string[]) => void; - workspaceConfigurableApps?: PublicAppInfo[]; -} - -export const WorkspaceFeatureSelector = ({ - selectedFeatures, - onChange, - workspaceConfigurableApps, -}: WorkspaceFeatureSelectorProps) => { - const featuresOrGroups = useMemo( - () => convertApplicationsToFeaturesOrGroups(workspaceConfigurableApps ?? []), - [workspaceConfigurableApps] - ); - - const handleFeatureChange = useCallback( - (featureId) => { - if (!selectedFeatures.includes(featureId)) { - onChange([...selectedFeatures, featureId]); - return; - } - onChange(selectedFeatures.filter((selectedId) => selectedId !== featureId)); - }, - [selectedFeatures, onChange] - ); - - const handleFeatureCheckboxChange = useCallback( - (e) => { - handleFeatureChange(e.target.id); - }, - [handleFeatureChange] - ); - - const handleFeatureGroupChange = useCallback( - (e) => { - const featureOrGroup = featuresOrGroups.find( - (item) => isWorkspaceFeatureGroup(item) && item.name === e.target.id - ); - if (!featureOrGroup || !isWorkspaceFeatureGroup(featureOrGroup)) { - return; - } - const groupFeatureIds = featureOrGroup.features.map((feature) => feature.id); - const notExistsIds = groupFeatureIds.filter((id) => !selectedFeatures.includes(id)); - // Check all not selected features if not been selected in current group. - if (notExistsIds.length > 0) { - onChange([...selectedFeatures, ...notExistsIds]); - return; - } - // Need to un-check these features, if all features in group has been selected - onChange(selectedFeatures.filter((featureId) => !groupFeatureIds.includes(featureId))); - }, - [featuresOrGroups, selectedFeatures, onChange] - ); - - return ( - <> - {featuresOrGroups.map((featureOrGroup) => { - const features = isWorkspaceFeatureGroup(featureOrGroup) ? featureOrGroup.features : []; - const selectedIds = selectedFeatures.filter((id) => - (isWorkspaceFeatureGroup(featureOrGroup) - ? featureOrGroup.features - : [featureOrGroup] - ).find((item) => item.id === id) - ); - const featureOrGroupId = isWorkspaceFeatureGroup(featureOrGroup) - ? featureOrGroup.name - : featureOrGroup.id; - - return ( - - -
- - {featureOrGroup.name} - -
-
- - 0 ? ` (${selectedIds.length}/${features.length})` : '' - }`} - checked={selectedIds.length > 0} - indeterminate={ - isWorkspaceFeatureGroup(featureOrGroup) && - selectedIds.length > 0 && - selectedIds.length < features.length - } - data-test-subj={`workspaceForm-workspaceFeatureVisibility-${featureOrGroupId}`} - /> - {isWorkspaceFeatureGroup(featureOrGroup) && ( - ({ - id: item.id, - label: item.name, - }))} - idToSelectedMap={selectedIds.reduce( - (previousValue, currentValue) => ({ - ...previousValue, - [currentValue]: true, - }), - {} - )} - onChange={handleFeatureChange} - style={{ marginLeft: 40 }} - data-test-subj={`workspaceForm-workspaceFeatureVisibility-featureWithCategory-${featureOrGroupId}`} - /> - )} - -
- ); - })} - - ); -}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index 794f983bd989..645e1843c9ab 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -13,19 +13,15 @@ import { EuiFieldText, EuiText, EuiColorPicker, - EuiHorizontalRule, - EuiTab, - EuiTabs, EuiTextArea, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { WorkspaceBottomBar } from './workspace_bottom_bar'; import { WorkspaceFormProps } from './types'; -import { WorkspaceFormTabs } from './constants'; import { useWorkspaceForm } from './use_workspace_form'; -import { WorkspaceFeatureSelector } from './workspace_feature_selector'; import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; +import { WorkspaceUseCase } from './workspace_use_case'; export const WorkspaceForm = (props: WorkspaceFormProps) => { const { @@ -33,31 +29,23 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { defaultValues, operationType, permissionEnabled, + workspaceConfigurableApps, permissionLastAdminItemDeletable, } = props; const { formId, formData, formErrors, - selectedTab, numberOfErrors, handleFormSubmit, handleColorChange, - handleFeaturesChange, + handleUseCasesChange, handleNameInputChange, - handleTabFeatureClick, setPermissionSettings, - handleTabPermissionClick, handleDescriptionChange, } = useWorkspaceForm(props); const workspaceDetailsTitle = i18n.translate('workspace.form.workspaceDetails.title', { - defaultMessage: 'Workspace Details', - }); - const featureVisibilityTitle = i18n.translate('workspace.form.featureVisibility.title', { - defaultMessage: 'Feature Visibility', - }); - const usersAndPermissionsTitle = i18n.translate('workspace.form.usersAndPermissions.title', { - defaultMessage: 'Users & Permissions', + defaultMessage: 'Enter Details', }); return ( @@ -66,7 +54,6 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => {

{workspaceDetailsTitle}

- { onChange={handleNameInputChange} readOnly={!!defaultValues?.reserved} data-test-subj="workspaceForm-workspaceDetails-nameInputText" + placeholder={i18n.translate('workspace.form.workspaceDetails.name.placeholder', { + defaultMessage: 'Enter a name', + })} /> { - - - + +

+ {i18n.translate('workspace.form.workspaceUseCase.title', { + defaultMessage: 'Choose one or more focus areas', + })} +

+
+ + - {featureVisibilityTitle} -
- {permissionEnabled && ( - - {usersAndPermissionsTitle} - - )} -
- {selectedTab === WorkspaceFormTabs.FeatureVisibility && ( - - -

{featureVisibilityTitle}

-
- - - -
- )} - {selectedTab === WorkspaceFormTabs.UsersAndPermissions && ( +
+ + + {permissionEnabled && (

{i18n.translate('workspace.form.usersAndPermissions.title', { - defaultMessage: 'Users & Permissions', + defaultMessage: 'Manage access and permissions', })}

- ) => { + const onChangeMock = jest.fn(); + const renderResult = render( + + ); + return { + renderResult, + onChangeMock, + }; +}; + +describe('WorkspaceUseCase', () => { + it('should render four use cases', () => { + const { renderResult } = setup(); + + expect(renderResult.getByText('Observability')).toBeInTheDocument(); + expect(renderResult.getByText('Analytics')).toBeInTheDocument(); + expect(renderResult.getByText('Security Analytics')).toBeInTheDocument(); + expect(renderResult.getByText('Search')).toBeInTheDocument(); + }); + + it('should call onChange with new added use case', () => { + const { renderResult, onChangeMock } = setup(); + + expect(onChangeMock).not.toHaveBeenCalled(); + fireEvent.click(renderResult.getByText('Observability')); + expect(onChangeMock).toHaveBeenLastCalledWith(['observability']); + }); + + it('should call onChange without removed use case', () => { + const { renderResult, onChangeMock } = setup({ value: ['observability'] }); + + expect(onChangeMock).not.toHaveBeenCalled(); + fireEvent.click(renderResult.getByText('Observability')); + expect(onChangeMock).toHaveBeenLastCalledWith([]); + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx new file mode 100644 index 000000000000..8e47d9eafc77 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx @@ -0,0 +1,99 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useMemo, useCallback } from 'react'; +import { PublicAppInfo } from 'opensearch-dashboards/public'; +import { EuiCheckableCard, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; + +import { WORKSPACE_USE_CASES } from '../../../common/constants'; +import './workspace_use_case.scss'; + +const ALL_USE_CASES = [ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.analytics, + WORKSPACE_USE_CASES.search, +]; + +interface WorkspaceUseCaseCardProps { + id: string; + title: string; + checked: boolean; + description: string; + onChange: (id: string) => void; +} + +const WorkspaceUseCaseCard = ({ + id, + title, + description, + checked, + onChange, +}: WorkspaceUseCaseCardProps) => { + const handleChange = useCallback(() => { + onChange(id); + }, [id, onChange]); + return ( + + + {description} + + + ); +}; + +export interface WorkspaceUseCaseProps { + configurableApps?: PublicAppInfo[]; + value: string[]; + onChange: (newValue: string[]) => void; +} + +export const WorkspaceUseCase = ({ configurableApps, value, onChange }: WorkspaceUseCaseProps) => { + const availableUseCases = useMemo(() => { + if (!configurableApps) { + return []; + } + const configurableAppsId = configurableApps.map((app) => app.id); + return ALL_USE_CASES.filter((useCase) => { + return useCase.features.some((featureId) => configurableAppsId.includes(featureId)); + }); + }, [configurableApps]); + + const handleCardChange = useCallback( + (id: string) => { + if (!value.includes(id)) { + onChange([...value, id]); + return; + } + onChange(value.filter((item) => item !== id)); + }, + [value, onChange] + ); + + return ( + + {availableUseCases.map(({ id, title, description }) => ( + + + + ))} + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap b/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap index f90101772950..375e320e6305 100644 --- a/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap +++ b/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap @@ -246,9 +246,9 @@ exports[`WorkspaceList should render title and table normally 1`] = ` > - Features + Use case diff --git a/src/plugins/workspace/public/components/workspace_list/index.test.tsx b/src/plugins/workspace/public/components/workspace_list/index.test.tsx index d75ddf0d513f..6cbf36e0c31e 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.test.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.test.tsx @@ -26,8 +26,9 @@ jest.mock('../delete_workspace_modal', () => ({ function getWrapWorkspaceListInContext( workspaceList = [ - { id: 'id1', name: 'name1' }, + { id: 'id1', name: 'name1', features: [] }, { id: 'id2', name: 'name2' }, + { id: 'id3', name: 'name3', features: ['use-case-observability'] }, ] ) { const coreStartMock = coreMock.createStart(); diff --git a/src/plugins/workspace/public/components/workspace_list/index.tsx b/src/plugins/workspace/public/components/workspace_list/index.tsx index b22a0fdb99fd..34027b87de5b 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.tsx @@ -22,10 +22,11 @@ import { WorkspaceAttribute } from '../../../../../core/public'; import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public'; import { switchWorkspace, navigateToWorkspaceUpdatePage } from '../utils/workspace'; -import { WORKSPACE_CREATE_APP_ID } from '../../../common/constants'; +import { WORKSPACE_CREATE_APP_ID, WORKSPACE_USE_CASES } from '../../../common/constants'; import { cleanWorkspaceId } from '../../../../../core/public'; import { DeleteWorkspaceModal } from '../delete_workspace_modal'; +import { getUseCaseFromFeatureConfig, isUseCaseFeatureConfig } from '../../utils'; const WORKSPACE_LIST_PAGE_DESCRIPTIOIN = i18n.translate('workspace.list.description', { defaultMessage: @@ -103,9 +104,22 @@ export const WorkspaceList = () => { }, { field: 'features', - name: 'Features', + name: 'Use case', isExpander: true, hasActions: true, + render: (features: string[]) => { + if (!features || features.length === 0) { + return ''; + } + const results: string[] = []; + features.forEach((featureConfig) => { + const useCaseId = getUseCaseFromFeatureConfig(featureConfig); + if (useCaseId) { + results.push(WORKSPACE_USE_CASES[useCaseId].title); + } + }); + return results.join(', '); + }, }, { name: 'Actions', diff --git a/src/plugins/workspace/public/components/workspace_overview/workspace_overview.test.tsx b/src/plugins/workspace/public/components/workspace_overview/workspace_overview.test.tsx index 64ff49fcbdd6..8a87510f0d9e 100644 --- a/src/plugins/workspace/public/components/workspace_overview/workspace_overview.test.tsx +++ b/src/plugins/workspace/public/components/workspace_overview/workspace_overview.test.tsx @@ -207,7 +207,7 @@ describe('WorkspaceOverview', () => { const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); const { getByText } = render(WorkspaceOverviewPage({ workspacesService: workspaceService })); fireEvent.click(getByText('Settings')); - expect(screen.queryByText('Workspace Details')).not.toBeNull(); + expect(screen.queryByText('Enter Details')).not.toBeNull(); // title is hidden expect(screen.queryByText('Update Workspace')).toBeNull(); }); diff --git a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx b/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx index 989e556afe4f..463db3591f9c 100644 --- a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx +++ b/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx @@ -17,11 +17,8 @@ const navigateToApp = jest.fn(); const notificationToastsAddSuccess = jest.fn(); const notificationToastsAddDanger = jest.fn(); const PublicAPPInfoMap = new Map([ - ['app1', { id: 'app1', title: 'app1' }], - ['app2', { id: 'app2', title: 'app2', category: { id: 'category1', label: 'category1' } }], - ['app3', { id: 'app3', category: { id: 'category1', label: 'category1' } }], - ['app4', { id: 'app4', category: { id: 'category2', label: 'category2' } }], - ['app5', { id: 'app5', category: { id: 'category2', label: 'category2' } }], + ['data-explorer', { id: 'data-explorer', title: 'Data Explorer' }], + ['dashboards', { id: 'dashboards', title: 'Dashboards' }], ]); const createWorkspacesSetupContractMockWithValue = () => { const currentWorkspaceId$ = new BehaviorSubject('abljlsds'); @@ -29,7 +26,7 @@ const createWorkspacesSetupContractMockWithValue = () => { id: 'abljlsds', name: 'test1', description: 'test1', - features: [], + features: ['use-case-observability'], color: '', icon: '', reserved: false, @@ -173,10 +170,9 @@ describe('WorkspaceUpdater', () => { target: { value: '#000000' }, }); - fireEvent.click(getByTestId('workspaceForm-workspaceFeatureVisibility-app1')); - fireEvent.click(getByTestId('workspaceForm-workspaceFeatureVisibility-category1')); + fireEvent.click(getByTestId('workspaceUseCase-observability')); + fireEvent.click(getByTestId('workspaceUseCase-analytics')); - fireEvent.click(getByText('Users & Permissions')); fireEvent.click(getByTestId('workspaceForm-permissionSettingPanel-user-addNew')); const userIdInput = getAllByText('Select')[0]; fireEvent.click(userIdInput); @@ -192,7 +188,7 @@ describe('WorkspaceUpdater', () => { name: 'test workspace name', color: '#000000', description: 'test workspace description', - features: expect.arrayContaining(['app1', 'app2', 'app3']), + features: expect.arrayContaining(['use-case-analytics']), }), { read: { diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 8c6bd2ddc0e6..969459e188ee 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -230,7 +230,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> core.application.register({ id: WORKSPACE_CREATE_APP_ID, title: i18n.translate('workspace.settings.workspaceCreate', { - defaultMessage: 'Create Workspace', + defaultMessage: 'Create a workspace', }), navLinkStatus: AppNavLinkStatus.hidden, async mount(params: AppMountParameters) { diff --git a/src/plugins/workspace/public/utils.test.ts b/src/plugins/workspace/public/utils.test.ts index c68dc844da2e..70eb91cfbdda 100644 --- a/src/plugins/workspace/public/utils.test.ts +++ b/src/plugins/workspace/public/utils.test.ts @@ -8,6 +8,7 @@ import { featureMatchesConfig, filterWorkspaceConfigurableApps, isAppAccessibleInWorkspace, + isFeatureIdInsideUseCase, } from './utils'; import { WorkspaceAvailability } from '../../../core/public'; @@ -96,6 +97,14 @@ describe('workspace utils: featureMatchesConfig', () => { true ); }); + + it('should match features include by any use cases', () => { + const match = featureMatchesConfig(['use-case-observability', 'use-case-analytics']); + expect(match({ id: 'dashboards' })).toBe(true); + expect(match({ id: 'observability-traces' })).toBe(true); + expect(match({ id: 'alerting' })).toBe(true); + expect(match({ id: 'not-in-any-use-case' })).toBe(false); + }); }); describe('workspace utils: isAppAccessibleInWorkspace', () => { @@ -261,3 +270,9 @@ describe('workspace utils: filterWorkspaceConfigurableApps', () => { expect(filteredApps[1].id).toEqual('management'); }); }); + +describe('workspace utils: isFeatureIdInsideUseCase', () => { + it('should return false for invalid use case', () => { + expect(isFeatureIdInsideUseCase('discover', 'use-case-invalid')).toBe(false); + }); +}); diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index ba9ab5399e21..eaf96c80a4df 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -12,7 +12,34 @@ import { WorkspaceObject, WorkspaceAvailability, } from '../../../core/public'; -import { DEFAULT_SELECTED_FEATURES_IDS } from '../common/constants'; +import { DEFAULT_SELECTED_FEATURES_IDS, WORKSPACE_USE_CASES } from '../common/constants'; + +const USE_CASE_PREFIX = 'use-case-'; + +export const getUseCaseFeatureConfig = (useCaseId: string) => `${USE_CASE_PREFIX}${useCaseId}`; + +export const isUseCaseFeatureConfig = (featureConfig: string) => + featureConfig.startsWith(USE_CASE_PREFIX); + +type WorkspaceUseCaseId = keyof typeof WORKSPACE_USE_CASES; + +export const getUseCaseFromFeatureConfig = (featureConfig: string) => { + if (isUseCaseFeatureConfig(featureConfig)) { + const useCaseId = featureConfig.substring(USE_CASE_PREFIX.length); + if (Object.keys(WORKSPACE_USE_CASES).includes(useCaseId)) { + return useCaseId as WorkspaceUseCaseId; + } + } + return null; +}; + +export const isFeatureIdInsideUseCase = (featureId: string, featureConfig: string) => { + const useCase = getUseCaseFromFeatureConfig(featureConfig); + if (useCase && useCase in WORKSPACE_USE_CASES) { + return WORKSPACE_USE_CASES[useCase].features.includes(featureId); + } + return false; +}; /** * Checks if a given feature matches the provided feature configuration. @@ -24,6 +51,8 @@ import { DEFAULT_SELECTED_FEATURES_IDS } from '../common/constants'; * 4. To exclude a feature or category, prepend with `!`, e.g., `!discover` or `!@management`. * 5. The order of featureConfig array matters. From left to right, later configs override the previous ones. * For example, ['!@management', '*'] matches any feature because '*' overrides the previous setting: '!@management'. + * 6. For feature id start with use case prefix, it will read use case's features and match every passed apps. + * For example, ['user-case-observability'] matches all features under observability use case. */ export const featureMatchesConfig = (featureConfigs: string[]) => ({ id, @@ -45,6 +74,14 @@ export const featureMatchesConfig = (featureConfigs: string[]) => ({ matched = true; } + // matches any feature inside use cases + if (getUseCaseFromFeatureConfig(featureConfig)) { + const isInsideUseCase = isFeatureIdInsideUseCase(id, featureConfig); + if (isInsideUseCase) { + matched = true; + } + } + // The config starts with `@` matches a category if (category && featureConfig === `@${category.id}`) { matched = true; From 831a5e5f8f8197c7dedb6590af2d176444f8f7a3 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 09:51:00 -0700 Subject: [PATCH 014/276] Update sidecar z-index style (#6964) (#6968) * update sidecar style * Changeset file for PR #6964 created/updated --------- (cherry picked from commit e7f28f4295521f53e76d09e4186b0c66d09d8148) Signed-off-by: tygao Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/6964.yml | 2 ++ src/core/public/overlays/sidecar/components/sidecar.scss | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/6964.yml diff --git a/changelogs/fragments/6964.yml b/changelogs/fragments/6964.yml new file mode 100644 index 000000000000..b028225e2800 --- /dev/null +++ b/changelogs/fragments/6964.yml @@ -0,0 +1,2 @@ +fix: +- Update z-index of sidecar container to make it more than mask, from 1000 to 1001. ([#6964](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6964)) \ No newline at end of file diff --git a/src/core/public/overlays/sidecar/components/sidecar.scss b/src/core/public/overlays/sidecar/components/sidecar.scss index 1878b92b5074..7041abe74fd3 100644 --- a/src/core/public/overlays/sidecar/components/sidecar.scss +++ b/src/core/public/overlays/sidecar/components/sidecar.scss @@ -6,7 +6,9 @@ .osdSidecarFlyout { box-shadow: initial; position: fixed; - z-index: 1000; + + // Sidecar z-index should more than mask. Actually will be 1001. + z-index: $euiZMaskBelowHeader + 1; background: lightOrDarkTheme($euiColorGhost, $euiColorInk); display: flex; From ee9dc5efd45610a6a2d257443e0e178566b4f998 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 7 Jun 2024 09:52:40 -0700 Subject: [PATCH 015/276] [CVE-2024-4067][CVE-2024-4068] Bump packages dependent on `braces` versions lower than 3.0.3 (#6911) (#6925) Bumped packages: * `@amoo-miki/webpack` to `4.46.0-xxhash.1` * `micromatch` to `4.0.7` * `@types/watchpack` to `2.4.4` * `watchpack` to `2.4.1` Removed: * `@types/globby` cherry-picked from 418bf192692627ce32f4b9c0fb1a4eca1c8f26f5 Signed-off-by: Miki --- .eslintrc.js | 34 +- changelogs/fragments/6911.yml | 2 + package.json | 5 +- packages/osd-ace/package.json | 2 +- .../package.json | 2 +- .../osd-eslint-plugin-eslint/package.json | 2 +- .../rules/no_restricted_paths.test.js | 28 +- packages/osd-interpreter/package.json | 2 +- packages/osd-monaco/package.json | 2 +- packages/osd-optimizer/package.json | 4 +- .../basic_optimization.test.ts | 2 +- .../integration_tests/bundle_cache.test.ts | 2 +- .../osd-optimizer/src/optimizer/watcher.ts | 8 +- packages/osd-pm/dist/index.js | 24029 +--------------- packages/osd-pm/package.json | 3 +- .../production/build_production_projects.ts | 1 - packages/osd-ui-shared-deps/package.json | 2 +- yarn.lock | 650 +- 18 files changed, 407 insertions(+), 24373 deletions(-) create mode 100644 changelogs/fragments/6911.yml diff --git a/.eslintrc.js b/.eslintrc.js index ad6cea998136..a78ddeca7813 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -272,26 +272,22 @@ module.exports = { basePath: __dirname, zones: [ { - target: ['(src)/**/*', '!src/core/**/*'], + target: ['src/**/*', '!src/core/**/*'], from: ['src/core/utils/**/*'], errorMessage: `Plugins may only import from src/core/server and src/core/public.`, }, { - target: ['(src)/plugins/*/server/**/*'], - from: ['(src)/plugins/*/public/**/*'], + target: ['src/plugins/*/server/**/*'], + from: ['src/plugins/*/public/**/*'], errorMessage: `Server code can not import from public, use a common directory.`, }, { - target: ['(src)/plugins/*/common/**/*'], - from: ['(src)/plugins/*/(server|public)/**/*'], + target: ['src/plugins/*/common/**/*'], + from: ['src/plugins/*/(server|public)/**/*'], errorMessage: `Common code can not import from server or public, use a common directory.`, }, { - target: [ - 'src/legacy/**/*', - '(src)/plugins/**/(public|server)/**/*', - 'examples/**/*', - ], + target: ['src/legacy/**/*', 'src/plugins/**/(public|server)/**/*', 'examples/**/*'], from: [ 'src/core/public/**/*', '!src/core/public/index.ts', // relative import @@ -320,22 +316,22 @@ module.exports = { { target: [ 'src/legacy/**/*', - '(src)/plugins/**/(public|server)/**/*', + 'src/plugins/**/(public|server)/**/*', 'examples/**/*', - '!(src)/**/*.test.*', + '!src/**/*.test.*', ], from: [ - '(src)/plugins/**/(public|server)/**/*', - '!(src)/plugins/**/(public|server)/mocks/index.{js,mjs,ts}', - '!(src)/plugins/**/(public|server)/(index|mocks).{js,mjs,ts,tsx}', + 'src/plugins/**/(public|server)/**/*', + '!src/plugins/**/(public|server)/mocks/index.{js,mjs,ts}', + '!src/plugins/**/(public|server)/(index|mocks).{js,mjs,ts,tsx}', ], allowSameFolder: true, errorMessage: 'Plugins may only import from top-level public and server modules.', }, { target: [ - '(src)/plugins/**/*', - '!(src)/plugins/**/server/**/*', + 'src/plugins/**/*', + '!src/plugins/**/server/**/*', 'examples/**/*', '!examples/**/server/**/*', @@ -343,7 +339,7 @@ module.exports = { from: [ 'src/core/server', 'src/core/server/**/*', - '(src)/plugins/*/server/**/*', + 'src/plugins/*/server/**/*', 'examples/**/server/**/*', ], errorMessage: @@ -355,7 +351,7 @@ module.exports = { errorMessage: 'The core cannot depend on any plugins.', }, { - target: ['(src)/plugins/*/public/**/*'], + target: ['src/plugins/*/public/**/*'], from: ['ui/**/*'], errorMessage: 'Plugins cannot import legacy UI code.', }, diff --git a/changelogs/fragments/6911.yml b/changelogs/fragments/6911.yml new file mode 100644 index 000000000000..ed4788f1cd8f --- /dev/null +++ b/changelogs/fragments/6911.yml @@ -0,0 +1,2 @@ +security: +- [CVE-2024-4067][CVE-2024-4068] Bump packages dependent on `braces` versions lower than 3.0.3 ([#6911](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6911)) diff --git a/package.json b/package.json index a0d2a58e445f..589426f08ab7 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "**/@types/node": "~18.7.0", "**/ansi-regex": "^5.0.1", "**/async": "^3.2.3", + "**/cpy/globby": "^10.0.1", "**/d3-color": "^3.1.0", "**/flat": "^5.0.2", "**/elasticsearch/agentkeepalive": "^4.5.0", @@ -110,11 +111,11 @@ "**/trim": "^0.0.3", "**/typescript": "4.0.2", "**/unset-value": "^2.0.1", + "**/watchpack-chokidar2/chokidar": "^3.5.3", "**/minimatch": "^3.0.5", "**/eslint-plugin-mocha-next/mocha": "npm:mocha@^10.1.0", "**/xml2js": "^0.5.0", "**/yaml": "^2.2.2" - }, "workspaces": { "packages": [ @@ -239,7 +240,6 @@ "uuid": "3.3.2", "whatwg-fetch": "^3.0.0", "yauzl": "^2.10.0" - }, "devDependencies": { "@babel/core": "^7.22.9", @@ -296,7 +296,6 @@ "@types/getopts": "^2.0.1", "@types/getos": "^3.0.0", "@types/glob": "^7.1.3", - "@types/globby": "^8.0.0", "@types/hapi__cookie": "^10.1.4", "@types/hapi__h2o2": "^8.3.3", "@types/hapi__hapi": "^20.0.10", diff --git a/packages/osd-ace/package.json b/packages/osd-ace/package.json index ae6c3126e99f..0778cbc40a12 100644 --- a/packages/osd-ace/package.json +++ b/packages/osd-ace/package.json @@ -14,7 +14,7 @@ "@osd/babel-preset": "1.0.0", "raw-loader": "^4.0.2", "typescript": "4.0.2", - "webpack": "npm:@amoo-miki/webpack@4.46.0-rc.2" + "webpack": "npm:@amoo-miki/webpack@4.46.0-xxhash.1" }, "@osd/pm": { "web": true diff --git a/packages/osd-eslint-import-resolver-opensearch-dashboards/package.json b/packages/osd-eslint-import-resolver-opensearch-dashboards/package.json index 2dfa00a516ba..fe6b8a19bb73 100755 --- a/packages/osd-eslint-import-resolver-opensearch-dashboards/package.json +++ b/packages/osd-eslint-import-resolver-opensearch-dashboards/package.json @@ -19,6 +19,6 @@ "glob-all": "^3.2.1", "lru-cache": "^4.1.5", "resolve": "^1.7.1", - "webpack": "npm:@amoo-miki/webpack@4.46.0-rc.2" + "webpack": "npm:@amoo-miki/webpack@4.46.0-xxhash.1" } } diff --git a/packages/osd-eslint-plugin-eslint/package.json b/packages/osd-eslint-plugin-eslint/package.json index 0e82fed704c6..85d21d02de14 100644 --- a/packages/osd-eslint-plugin-eslint/package.json +++ b/packages/osd-eslint-plugin-eslint/package.json @@ -11,7 +11,7 @@ "babel-eslint": "^10.0.3" }, "dependencies": { - "micromatch": "3.1.10", + "micromatch": "^4.0.7", "dedent": "^0.7.0", "eslint-module-utils": "2.5.0" } diff --git a/packages/osd-eslint-plugin-eslint/rules/no_restricted_paths.test.js b/packages/osd-eslint-plugin-eslint/rules/no_restricted_paths.test.js index 96251e8fe55c..0cc452043b45 100644 --- a/packages/osd-eslint-plugin-eslint/rules/no_restricted_paths.test.js +++ b/packages/osd-eslint-plugin-eslint/rules/no_restricted_paths.test.js @@ -370,7 +370,7 @@ ruleTester.run('@osd/eslint/no-restricted-paths', rule, { }, { - // Does not allow to import deeply within Core, using "src/core/..." Webpack alias. + // Does not allow to require deeply within Core, using "src/core/..." Webpack alias. code: 'const d = require("src/core/server/saved_objects")', filename: path.join(__dirname, './testfiles/no_restricted_paths/client/a.js'), options: [ @@ -393,6 +393,32 @@ ruleTester.run('@osd/eslint/no-restricted-paths', rule, { ], }, + { + // Does not allow to import deeply within Core, using "src/core/...". + code: ` + import { X as XX } from 'src/core/public'; + import { X as XY } from 'src/core/server';`, + filename: path.join(__dirname, './testfiles/no_restricted_paths/client/a.js'), + options: [ + { + basePath: __dirname, + zones: [ + { + target: ['**/testfiles/**/*', '!**/testfiles/**/server/**/*'], + from: ['src/core/server', 'src/core/server/**/*'], + }, + ], + }, + ], + errors: [ + { + message: 'Unexpected path "src/core/server" imported in restricted zone.', + line: 3, + column: 31, + }, + ], + }, + { // Does not allow to import "ui/kfetch". code: 'const d = require("ui/kfetch")', diff --git a/packages/osd-interpreter/package.json b/packages/osd-interpreter/package.json index 34bcad460244..4bf4b61d9835 100644 --- a/packages/osd-interpreter/package.json +++ b/packages/osd-interpreter/package.json @@ -31,7 +31,7 @@ "style-loader": "^1.1.3", "supports-color": "^7.0.0", "url-loader": "^2.2.0", - "webpack": "npm:@amoo-miki/webpack@4.46.0-rc.2", + "webpack": "npm:@amoo-miki/webpack@4.46.0-xxhash.1", "webpack-cli": "^4.9.2" } } diff --git a/packages/osd-monaco/package.json b/packages/osd-monaco/package.json index ae9cfaddc53a..0c9a459d129b 100644 --- a/packages/osd-monaco/package.json +++ b/packages/osd-monaco/package.json @@ -22,7 +22,7 @@ "raw-loader": "^4.0.2", "supports-color": "^7.0.0", "typescript": "4.0.2", - "webpack": "npm:@amoo-miki/webpack@4.46.0-rc.2", + "webpack": "npm:@amoo-miki/webpack@4.46.0-xxhash.1", "webpack-cli": "^4.9.2" } } diff --git a/packages/osd-optimizer/package.json b/packages/osd-optimizer/package.json index b1477f176358..853075556e96 100644 --- a/packages/osd-optimizer/package.json +++ b/packages/osd-optimizer/package.json @@ -45,7 +45,7 @@ "@types/compression-webpack-plugin": "^6.0.6", "@types/loader-utils": "^1.1.3", "@types/source-map-support": "^0.5.3", - "@types/watchpack": "^1.1.6", + "@types/watchpack": "^2.4.4", "@types/webpack": "^4.41.31", "babel-loader": "^8.2.3", "comment-stripper": "^0.0.4", @@ -59,6 +59,6 @@ "style-loader": "^1.1.3", "url-loader": "^2.2.0", "val-loader": "^2.1.2", - "webpack": "npm:@amoo-miki/webpack@4.46.0-rc.2" + "webpack": "npm:@amoo-miki/webpack@4.46.0-xxhash.1" } } diff --git a/packages/osd-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/osd-optimizer/src/integration_tests/basic_optimization.test.ts index 9b32e4efe6b0..8cca53f7c1a6 100644 --- a/packages/osd-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/osd-optimizer/src/integration_tests/basic_optimization.test.ts @@ -74,7 +74,7 @@ beforeAll(async () => { await cpy('**/*', MOCK_REPO_DIR, { cwd: MOCK_REPO_SRC, parents: true, - deep: true, + deep: Infinity, }); }); diff --git a/packages/osd-optimizer/src/integration_tests/bundle_cache.test.ts b/packages/osd-optimizer/src/integration_tests/bundle_cache.test.ts index 24ddfd14a832..83a503a21e7e 100644 --- a/packages/osd-optimizer/src/integration_tests/bundle_cache.test.ts +++ b/packages/osd-optimizer/src/integration_tests/bundle_cache.test.ts @@ -54,7 +54,7 @@ beforeEach(async () => { await cpy('**/*', MOCK_REPO_DIR, { cwd: MOCK_REPO_SRC, parents: true, - deep: true, + deep: Infinity, }); }); diff --git a/packages/osd-optimizer/src/optimizer/watcher.ts b/packages/osd-optimizer/src/optimizer/watcher.ts index cf5faadb33d8..87f2ba2b8894 100644 --- a/packages/osd-optimizer/src/optimizer/watcher.ts +++ b/packages/osd-optimizer/src/optimizer/watcher.ts @@ -94,7 +94,7 @@ export class Watcher { take(1) ), - // call watchpack.watch after listerners are setup + // call watchpack.watch after listeners are set up Rx.defer(() => { const watchPaths: string[] = []; @@ -104,7 +104,11 @@ export class Watcher { } } - this.watchpack.watch(watchPaths, [], startTime); + this.watchpack.watch({ + files: watchPaths, + startTime, + }); + return Rx.EMPTY; }) ); diff --git a/packages/osd-pm/dist/index.js b/packages/osd-pm/dist/index.js index fcb50d8f06c9..cf943af712b0 100644 --- a/packages/osd-pm/dist/index.js +++ b/packages/osd-pm/dist/index.js @@ -43031,8 +43031,8 @@ const braces = (input, options = {}) => { let output = []; if (Array.isArray(input)) { - for (let pattern of input) { - let result = braces.create(pattern, options); + for (const pattern of input) { + const result = braces.create(pattern, options); if (Array.isArray(result)) { output.push(...result); } else { @@ -43166,7 +43166,7 @@ braces.create = (input, options = {}) => { return [input]; } - return options.expand !== true + return options.expand !== true ? braces.compile(input, options) : braces.expand(input, options); }; @@ -43188,9 +43188,9 @@ module.exports = braces; const utils = __webpack_require__(369); module.exports = (ast, options = {}) => { - let stringify = (node, parent = {}) => { - let invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent); - let invalidNode = node.invalid === true && options.escapeInvalid === true; + const stringify = (node, parent = {}) => { + const invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent); + const invalidNode = node.invalid === true && options.escapeInvalid === true; let output = ''; if (node.value) { @@ -43205,7 +43205,7 @@ module.exports = (ast, options = {}) => { } if (node.nodes) { - for (let child of node.nodes) { + for (const child of node.nodes) { output += stringify(child); } } @@ -43255,7 +43255,7 @@ exports.exceedsLimit = (min, max, step = 1, limit) => { */ exports.escapeNode = (block, n = 0, type) => { - let node = block.nodes[n]; + const node = block.nodes[n]; if (!node) return; if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { @@ -43324,13 +43324,23 @@ exports.reduce = nodes => nodes.reduce((acc, node) => { exports.flatten = (...args) => { const result = []; + const flat = arr => { for (let i = 0; i < arr.length; i++) { - let ele = arr[i]; - Array.isArray(ele) ? flat(ele, result) : ele !== void 0 && result.push(ele); + const ele = arr[i]; + + if (Array.isArray(ele)) { + flat(ele); + continue; + } + + if (ele !== undefined) { + result.push(ele); + } } return result; }; + flat(args); return result; }; @@ -43347,30 +43357,32 @@ const fill = __webpack_require__(371); const utils = __webpack_require__(369); const compile = (ast, options = {}) => { - let walk = (node, parent = {}) => { - let invalidBlock = utils.isInvalidBrace(parent); - let invalidNode = node.invalid === true && options.escapeInvalid === true; - let invalid = invalidBlock === true || invalidNode === true; - let prefix = options.escapeInvalid === true ? '\\' : ''; + const walk = (node, parent = {}) => { + const invalidBlock = utils.isInvalidBrace(parent); + const invalidNode = node.invalid === true && options.escapeInvalid === true; + const invalid = invalidBlock === true || invalidNode === true; + const prefix = options.escapeInvalid === true ? '\\' : ''; let output = ''; if (node.isOpen === true) { return prefix + node.value; } + if (node.isClose === true) { + console.log('node.isClose', prefix, node.value); return prefix + node.value; } if (node.type === 'open') { - return invalid ? (prefix + node.value) : '('; + return invalid ? prefix + node.value : '('; } if (node.type === 'close') { - return invalid ? (prefix + node.value) : ')'; + return invalid ? prefix + node.value : ')'; } if (node.type === 'comma') { - return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|'); + return node.prev.type === 'comma' ? '' : invalid ? node.value : '|'; } if (node.value) { @@ -43378,8 +43390,8 @@ const compile = (ast, options = {}) => { } if (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); - let range = fill(...args, { ...options, wrap: false, toRegex: true }); + const args = utils.reduce(node.nodes); + const range = fill(...args, { ...options, wrap: false, toRegex: true, strictZeros: true }); if (range.length !== 0) { return args.length > 1 && range.length > 1 ? `(${range})` : range; @@ -43387,10 +43399,11 @@ const compile = (ast, options = {}) => { } if (node.nodes) { - for (let child of node.nodes) { + for (const child of node.nodes) { output += walk(child, node); } } + return output; }; @@ -43467,7 +43480,7 @@ const toMaxLen = (input, maxLength) => { return negative ? ('-' + input) : input; }; -const toSequence = (parts, options) => { +const toSequence = (parts, options, maxLen) => { parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); @@ -43477,11 +43490,11 @@ const toSequence = (parts, options) => { let result; if (parts.positives.length) { - positives = parts.positives.join('|'); + positives = parts.positives.map(v => toMaxLen(String(v), maxLen)).join('|'); } if (parts.negatives.length) { - negatives = `-(${prefix}${parts.negatives.join('|')})`; + negatives = `-(${prefix}${parts.negatives.map(v => toMaxLen(String(v), maxLen)).join('|')})`; } if (positives && negatives) { @@ -43579,7 +43592,7 @@ const fillNumbers = (start, end, step = 1, options = {}) => { if (options.toRegex === true) { return step > 1 - ? toSequence(parts, options) + ? toSequence(parts, options, maxLen) : toRegex(range, null, { wrap: false, ...options }); } @@ -43591,7 +43604,6 @@ const fillLetters = (start, end, step = 1, options = {}) => { return invalidRange(start, end, options); } - let format = options.transform || (val => String.fromCharCode(val)); let a = `${start}`.charCodeAt(0); let b = `${end}`.charCodeAt(0); @@ -43988,7 +44000,7 @@ const stringify = __webpack_require__(368); const utils = __webpack_require__(369); const append = (queue = '', stash = '', enclose = false) => { - let result = []; + const result = []; queue = [].concat(queue); stash = [].concat(stash); @@ -43998,15 +44010,15 @@ const append = (queue = '', stash = '', enclose = false) => { return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; } - for (let item of queue) { + for (const item of queue) { if (Array.isArray(item)) { - for (let value of item) { + for (const value of item) { result.push(append(value, stash, enclose)); } } else { for (let ele of stash) { if (enclose === true && typeof ele === 'string') ele = `{${ele}}`; - result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele)); + result.push(Array.isArray(ele) ? append(item, ele, enclose) : item + ele); } } } @@ -44014,9 +44026,9 @@ const append = (queue = '', stash = '', enclose = false) => { }; const expand = (ast, options = {}) => { - let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; + const rangeLimit = options.rangeLimit === undefined ? 1000 : options.rangeLimit; - let walk = (node, parent = {}) => { + const walk = (node, parent = {}) => { node.queue = []; let p = parent; @@ -44038,7 +44050,7 @@ const expand = (ast, options = {}) => { } if (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); + const args = utils.reduce(node.nodes); if (utils.exceedsLimit(...args, options.step, rangeLimit)) { throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); @@ -44054,7 +44066,7 @@ const expand = (ast, options = {}) => { return; } - let enclose = utils.encloseBrace(node); + const enclose = utils.encloseBrace(node); let queue = node.queue; let block = node; @@ -44064,7 +44076,7 @@ const expand = (ast, options = {}) => { } for (let i = 0; i < node.nodes.length; i++) { - let child = node.nodes[i]; + const child = node.nodes[i]; if (child.type === 'comma' && node.type === 'brace') { if (i === 1) queue.push(''); @@ -44136,22 +44148,21 @@ const parse = (input, options = {}) => { throw new TypeError('Expected a string'); } - let opts = options || {}; - let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; + const opts = options || {}; + const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; if (input.length > max) { throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`); } - let ast = { type: 'root', input, nodes: [] }; - let stack = [ast]; + const ast = { type: 'root', input, nodes: [] }; + const stack = [ast]; let block = ast; let prev = ast; let brackets = 0; - let length = input.length; + const length = input.length; let index = 0; let depth = 0; let value; - let memo = {}; /** * Helpers @@ -44214,7 +44225,6 @@ const parse = (input, options = {}) => { if (value === CHAR_LEFT_SQUARE_BRACKET) { brackets++; - let closed = true; let next; while (index < length && (next = advance())) { @@ -44270,7 +44280,7 @@ const parse = (input, options = {}) => { */ if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { - let open = value; + const open = value; let next; if (options.keepQuotes !== true) { @@ -44302,8 +44312,8 @@ const parse = (input, options = {}) => { if (value === CHAR_LEFT_CURLY_BRACE) { depth++; - let dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; - let brace = { + const dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; + const brace = { type: 'brace', open: true, close: false, @@ -44330,7 +44340,7 @@ const parse = (input, options = {}) => { continue; } - let type = 'close'; + const type = 'close'; block = stack.pop(); block.close = true; @@ -44348,7 +44358,7 @@ const parse = (input, options = {}) => { if (value === CHAR_COMMA && depth > 0) { if (block.ranges > 0) { block.ranges = 0; - let open = block.nodes.shift(); + const open = block.nodes.shift(); block.nodes = [open, { type: 'text', value: stringify(block) }]; } @@ -44362,7 +44372,7 @@ const parse = (input, options = {}) => { */ if (value === CHAR_DOT && depth > 0 && block.commas === 0) { - let siblings = block.nodes; + const siblings = block.nodes; if (depth === 0 || siblings.length === 0) { push({ type: 'text', value }); @@ -44389,7 +44399,7 @@ const parse = (input, options = {}) => { if (prev.type === 'range') { siblings.pop(); - let before = siblings[siblings.length - 1]; + const before = siblings[siblings.length - 1]; before.value += prev.value + value; prev = before; block.ranges--; @@ -44422,8 +44432,8 @@ const parse = (input, options = {}) => { }); // get the location of the block on parent.nodes (block's siblings) - let parent = stack[stack.length - 1]; - let index = parent.nodes.indexOf(block); + const parent = stack[stack.length - 1]; + const index = parent.nodes.indexOf(block); // replace the (invalid) block with it's nodes parent.nodes.splice(index, 1, ...block.nodes); } @@ -44444,7 +44454,7 @@ module.exports = parse; module.exports = { - MAX_LENGTH: 1024 * 64, + MAX_LENGTH: 10000, // Digits CHAR_0: '0', /* 0 */ @@ -59124,7 +59134,6 @@ async function copyToBuild(project, opensearchDashboardsRoot, buildRoot) { await (0, _cpy.default)(['**/*', '!node_modules/**'], buildProjectPath, { cwd: project.getIntermediateBuildDirectory(), dot: true, - nodir: true, parents: true }); @@ -59151,11 +59160,11 @@ const os = __webpack_require__(121); const pMap = __webpack_require__(571); const arrify = __webpack_require__(567); const globby = __webpack_require__(572); -const hasGlob = __webpack_require__(752); -const cpFile = __webpack_require__(754); -const junk = __webpack_require__(763); -const pFilter = __webpack_require__(764); -const CpyError = __webpack_require__(766); +const hasGlob = __webpack_require__(575); +const cpFile = __webpack_require__(577); +const junk = __webpack_require__(586); +const pFilter = __webpack_require__(587); +const CpyError = __webpack_require__(589); const defaultOptions = { ignoreJunk: true @@ -59400,28 +59409,43 @@ module.exports = async ( "use strict"; const fs = __webpack_require__(134); -const arrayUnion = __webpack_require__(573); +const arrayUnion = __webpack_require__(353); +const merge2 = __webpack_require__(354); const glob = __webpack_require__(148); -const fastGlob = __webpack_require__(575); -const dirGlob = __webpack_require__(746); -const gitignore = __webpack_require__(749); +const fastGlob = __webpack_require__(355); +const dirGlob = __webpack_require__(427); +const gitignore = __webpack_require__(573); +const {FilterStream, UniqueStream} = __webpack_require__(574); const DEFAULT_FILTER = () => false; const isNegative = pattern => pattern[0] === '!'; const assertPatternsInput = patterns => { - if (!patterns.every(x => typeof x === 'string')) { + if (!patterns.every(pattern => typeof pattern === 'string')) { throw new TypeError('Patterns must be a string or an array of strings'); } }; -const checkCwdOption = options => { - if (options && options.cwd && !fs.statSync(options.cwd).isDirectory()) { +const checkCwdOption = (options = {}) => { + if (!options.cwd) { + return; + } + + let stat; + try { + stat = fs.statSync(options.cwd); + } catch (_) { + return; + } + + if (!stat.isDirectory()) { throw new Error('The `cwd` option must be a path to a directory'); } }; +const getPathString = p => p.stats instanceof fs.Stats ? p.path : p; + const generateGlobTasks = (patterns, taskOptions) => { patterns = arrayUnion([].concat(patterns)); assertPatternsInput(patterns); @@ -59429,27 +59453,29 @@ const generateGlobTasks = (patterns, taskOptions) => { const globTasks = []; - taskOptions = Object.assign({ + taskOptions = { ignore: [], - expandDirectories: true - }, taskOptions); + expandDirectories: true, + ...taskOptions + }; - patterns.forEach((pattern, i) => { + for (const [index, pattern] of patterns.entries()) { if (isNegative(pattern)) { - return; + continue; } const ignore = patterns - .slice(i) + .slice(index) .filter(isNegative) .map(pattern => pattern.slice(1)); - const options = Object.assign({}, taskOptions, { + const options = { + ...taskOptions, ignore: taskOptions.ignore.concat(ignore) - }); + }; globTasks.push({pattern, options}); - }); + } return globTasks; }; @@ -59461,9 +59487,15 @@ const globDirs = (task, fn) => { } if (Array.isArray(task.options.expandDirectories)) { - options = Object.assign(options, {files: task.options.expandDirectories}); + options = { + ...options, + files: task.options.expandDirectories + }; } else if (typeof task.options.expandDirectories === 'object') { - options = Object.assign(options, task.options.expandDirectories); + options = { + ...options, + ...task.options.expandDirectories + }; } return fn(task.pattern, options); @@ -59471,6 +59503,12 @@ const globDirs = (task, fn) => { const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern]; +const getFilterSync = options => { + return options && options.gitignore ? + gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER; +}; + const globToTask = task => glob => { const {options} = task; if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { @@ -59483,60 +59521,61 @@ const globToTask = task => glob => { }; }; -const globby = (patterns, options) => { - let globTasks; +module.exports = async (patterns, options) => { + const globTasks = generateGlobTasks(patterns, options); - try { - globTasks = generateGlobTasks(patterns, options); - } catch (error) { - return Promise.reject(error); - } + const getFilter = async () => { + return options && options.gitignore ? + gitignore({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER; + }; - const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob)) - .then(globs => Promise.all(globs.map(globToTask(task)))) - )) - .then(tasks => arrayUnion(...tasks)); + const getTasks = async () => { + const tasks = await Promise.all(globTasks.map(async task => { + const globs = await getPattern(task, dirGlob); + return Promise.all(globs.map(globToTask(task))); + })); - const getFilter = () => { - return Promise.resolve( - options && options.gitignore ? - gitignore({cwd: options.cwd, ignore: options.ignore}) : - DEFAULT_FILTER - ); + return arrayUnion(...tasks); }; - return getFilter() - .then(filter => { - return getTasks - .then(tasks => Promise.all(tasks.map(task => fastGlob(task.pattern, task.options)))) - .then(paths => arrayUnion(...paths)) - .then(paths => paths.filter(p => !filter(p))); - }); -}; + const [filter, tasks] = await Promise.all([getFilter(), getTasks()]); + const paths = await Promise.all(tasks.map(task => fastGlob(task.pattern, task.options))); -module.exports = globby; -// TODO: Remove this for the next major release -module.exports.default = globby; + return arrayUnion(...paths).filter(path_ => !filter(getPathString(path_))); +}; module.exports.sync = (patterns, options) => { const globTasks = generateGlobTasks(patterns, options); - const getFilter = () => { - return options && options.gitignore ? - gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : - DEFAULT_FILTER; - }; - const tasks = globTasks.reduce((tasks, task) => { const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); return tasks.concat(newTask); }, []); - const filter = getFilter(); + const filter = getFilterSync(options); + return tasks.reduce( (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), [] - ).filter(p => !filter(p)); + ).filter(path_ => !filter(path_)); +}; + +module.exports.stream = (patterns, options) => { + const globTasks = generateGlobTasks(patterns, options); + + const tasks = globTasks.reduce((tasks, task) => { + const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); + return tasks.concat(newTask); + }, []); + + const filter = getFilterSync(options); + const filterStream = new FilterStream(p => !filter(p)); + const uniqueStream = new UniqueStream(); + + return merge2(tasks.map(task => fastGlob.stream(task.pattern, task.options))) + .pipe(filterStream) + .pipe(uniqueStream); }; module.exports.generateGlobTasks = generateGlobTasks; @@ -59554,23637 +59593,179 @@ module.exports.gitignore = gitignore; "use strict"; -var arrayUniq = __webpack_require__(574); +const {promisify} = __webpack_require__(112); +const fs = __webpack_require__(134); +const path = __webpack_require__(4); +const fastGlob = __webpack_require__(355); +const gitIgnore = __webpack_require__(430); +const slash = __webpack_require__(431); -module.exports = function () { - return arrayUniq([].concat.apply([], arguments)); -}; +const DEFAULT_IGNORE = [ + '**/node_modules/**', + '**/flow-typed/**', + '**/coverage/**', + '**/.git' +]; +const readFileP = promisify(fs.readFile); -/***/ }), -/* 574 */ -/***/ (function(module, exports, __webpack_require__) { +const mapGitIgnorePatternTo = base => ignore => { + if (ignore.startsWith('!')) { + return '!' + path.posix.join(base, ignore.slice(1)); + } -"use strict"; + return path.posix.join(base, ignore); +}; +const parseGitIgnore = (content, options) => { + const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); -// there's 3 implementations written in increasing order of efficiency + return content + .split(/\r?\n/) + .filter(Boolean) + .filter(line => !line.startsWith('#')) + .map(mapGitIgnorePatternTo(base)); +}; -// 1 - no Set type is defined -function uniqNoSet(arr) { - var ret = []; +const reduceIgnore = files => { + return files.reduce((ignores, file) => { + ignores.add(parseGitIgnore(file.content, { + cwd: file.cwd, + fileName: file.filePath + })); + return ignores; + }, gitIgnore()); +}; - for (var i = 0; i < arr.length; i++) { - if (ret.indexOf(arr[i]) === -1) { - ret.push(arr[i]); +const ensureAbsolutePathForCwd = (cwd, p) => { + if (path.isAbsolute(p)) { + if (p.startsWith(cwd)) { + return p; } - } - return ret; -} + throw new Error(`Path ${p} is not in cwd ${cwd}`); + } -// 2 - a simple Set type is defined -function uniqSet(arr) { - var seen = new Set(); - return arr.filter(function (el) { - if (!seen.has(el)) { - seen.add(el); - return true; - } + return path.join(cwd, p); +}; - return false; - }); -} +const getIsIgnoredPredecate = (ignores, cwd) => { + return p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, p)))); +}; -// 3 - a standard Set type is defined and it has a forEach method -function uniqSetWithForEach(arr) { - var ret = []; +const getFile = async (file, cwd) => { + const filePath = path.join(cwd, file); + const content = await readFileP(filePath, 'utf8'); - (new Set(arr)).forEach(function (el) { - ret.push(el); - }); + return { + cwd, + filePath, + content + }; +}; - return ret; -} +const getFileSync = (file, cwd) => { + const filePath = path.join(cwd, file); + const content = fs.readFileSync(filePath, 'utf8'); -// V8 currently has a broken implementation -// https://github.com/joyent/node/issues/8449 -function doesForEachActuallyWork() { - var ret = false; + return { + cwd, + filePath, + content + }; +}; - (new Set([true])).forEach(function (el) { - ret = el; - }); +const normalizeOptions = ({ + ignore = [], + cwd = slash(process.cwd()) +} = {}) => { + return {ignore, cwd}; +}; - return ret === true; -} +module.exports = async options => { + options = normalizeOptions(options); -if ('Set' in global) { - if (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) { - module.exports = uniqSetWithForEach; - } else { - module.exports = uniqSet; - } -} else { - module.exports = uniqNoSet; -} + const paths = await fastGlob('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }); + const files = await Promise.all(paths.map(file => getFile(file, options.cwd))); + const ignores = reduceIgnore(files); -/***/ }), -/* 575 */ -/***/ (function(module, exports, __webpack_require__) { + return getIsIgnoredPredecate(ignores, options.cwd); +}; -const pkg = __webpack_require__(576); +module.exports.sync = options => { + options = normalizeOptions(options); -module.exports = pkg.async; -module.exports.default = pkg.async; + const paths = fastGlob.sync('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }); -module.exports.async = pkg.async; -module.exports.sync = pkg.sync; -module.exports.stream = pkg.stream; + const files = paths.map(file => getFileSync(file, options.cwd)); + const ignores = reduceIgnore(files); -module.exports.generateTasks = pkg.generateTasks; + return getIsIgnoredPredecate(ignores, options.cwd); +}; /***/ }), -/* 576 */ +/* 574 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(577); -var taskManager = __webpack_require__(578); -var reader_async_1 = __webpack_require__(717); -var reader_stream_1 = __webpack_require__(741); -var reader_sync_1 = __webpack_require__(742); -var arrayUtils = __webpack_require__(744); -var streamUtils = __webpack_require__(745); -/** - * Synchronous API. - */ -function sync(source, opts) { - assertPatternsInput(source); - var works = getWorks(source, reader_sync_1.default, opts); - return arrayUtils.flatten(works); -} -exports.sync = sync; -/** - * Asynchronous API. - */ -function async(source, opts) { - try { - assertPatternsInput(source); - } - catch (error) { - return Promise.reject(error); - } - var works = getWorks(source, reader_async_1.default, opts); - return Promise.all(works).then(arrayUtils.flatten); -} -exports.async = async; -/** - * Stream API. - */ -function stream(source, opts) { - assertPatternsInput(source); - var works = getWorks(source, reader_stream_1.default, opts); - return streamUtils.merge(works); -} -exports.stream = stream; -/** - * Return a set of tasks based on provided patterns. - */ -function generateTasks(source, opts) { - assertPatternsInput(source); - var patterns = [].concat(source); - var options = optionsManager.prepare(opts); - return taskManager.generate(patterns, options); -} -exports.generateTasks = generateTasks; -/** - * Returns a set of works based on provided tasks and class of the reader. - */ -function getWorks(source, _Reader, opts) { - var patterns = [].concat(source); - var options = optionsManager.prepare(opts); - var tasks = taskManager.generate(patterns, options); - var reader = new _Reader(options); - return tasks.map(reader.read, reader); -} -function assertPatternsInput(source) { - if ([].concat(source).every(isString)) { - return; - } - throw new TypeError('Patterns must be a string or an array of strings'); -} -function isString(source) { - /* tslint:disable-next-line strict-type-predicates */ - return typeof source === 'string'; -} +const {Transform} = __webpack_require__(138); -/***/ }), -/* 577 */ -/***/ (function(module, exports, __webpack_require__) { +class ObjectTransform extends Transform { + constructor() { + super({ + objectMode: true + }); + } +} -"use strict"; - -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -function prepare(options) { - var opts = __assign({ cwd: process.cwd(), deep: true, ignore: [], dot: false, stats: false, onlyFiles: true, onlyDirectories: false, followSymlinkedDirectories: true, unique: true, markDirectories: false, absolute: false, nobrace: false, brace: true, noglobstar: false, globstar: true, noext: false, extension: true, nocase: false, case: true, matchBase: false, transform: null }, options); - if (opts.onlyDirectories) { - opts.onlyFiles = false; - } - opts.brace = !opts.nobrace; - opts.globstar = !opts.noglobstar; - opts.extension = !opts.noext; - opts.case = !opts.nocase; - if (options) { - opts.brace = ('brace' in options ? options.brace : opts.brace); - opts.globstar = ('globstar' in options ? options.globstar : opts.globstar); - opts.extension = ('extension' in options ? options.extension : opts.extension); - opts.case = ('case' in options ? options.case : opts.case); - } - return opts; -} -exports.prepare = prepare; - - -/***/ }), -/* 578 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(579); -/** - * Generate tasks based on parent directory of each pattern. - */ -function generate(patterns, options) { - var unixPatterns = patterns.map(patternUtils.unixifyPattern); - var unixIgnore = options.ignore.map(patternUtils.unixifyPattern); - var positivePatterns = getPositivePatterns(unixPatterns); - var negativePatterns = getNegativePatternsAsPositive(unixPatterns, unixIgnore); - /** - * When the `case` option is disabled, all patterns must be marked as dynamic, because we cannot check filepath - * directly (without read directory). - */ - var staticPatterns = !options.case ? [] : positivePatterns.filter(patternUtils.isStaticPattern); - var dynamicPatterns = !options.case ? positivePatterns : positivePatterns.filter(patternUtils.isDynamicPattern); - var staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false); - var dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true); - return staticTasks.concat(dynamicTasks); -} -exports.generate = generate; -/** - * Convert patterns to tasks based on parent directory of each pattern. - */ -function convertPatternsToTasks(positive, negative, dynamic) { - var positivePatternsGroup = groupPatternsByBaseDirectory(positive); - // When we have a global group – there is no reason to divide the patterns into independent tasks. - // In this case, the global task covers the rest. - if ('.' in positivePatternsGroup) { - var task = convertPatternGroupToTask('.', positive, negative, dynamic); - return [task]; - } - return convertPatternGroupsToTasks(positivePatternsGroup, negative, dynamic); -} -exports.convertPatternsToTasks = convertPatternsToTasks; -/** - * Return only positive patterns. - */ -function getPositivePatterns(patterns) { - return patternUtils.getPositivePatterns(patterns); -} -exports.getPositivePatterns = getPositivePatterns; -/** - * Return only negative patterns. - */ -function getNegativePatternsAsPositive(patterns, ignore) { - var negative = patternUtils.getNegativePatterns(patterns).concat(ignore); - var positive = negative.map(patternUtils.convertToPositivePattern); - return positive; -} -exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive; -/** - * Group patterns by base directory of each pattern. - */ -function groupPatternsByBaseDirectory(patterns) { - return patterns.reduce(function (collection, pattern) { - var base = patternUtils.getBaseDirectory(pattern); - if (base in collection) { - collection[base].push(pattern); - } - else { - collection[base] = [pattern]; - } - return collection; - }, {}); -} -exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; -/** - * Convert group of patterns to tasks. - */ -function convertPatternGroupsToTasks(positive, negative, dynamic) { - return Object.keys(positive).map(function (base) { - return convertPatternGroupToTask(base, positive[base], negative, dynamic); - }); -} -exports.convertPatternGroupsToTasks = convertPatternGroupsToTasks; -/** - * Create a task for positive and negative patterns. - */ -function convertPatternGroupToTask(base, positive, negative, dynamic) { - return { - base: base, - dynamic: dynamic, - positive: positive, - negative: negative, - patterns: [].concat(positive, negative.map(patternUtils.convertToNegativePattern)) - }; -} -exports.convertPatternGroupToTask = convertPatternGroupToTask; - - -/***/ }), -/* 579 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(4); -var globParent = __webpack_require__(363); -var isGlob = __webpack_require__(364); -var micromatch = __webpack_require__(580); -var GLOBSTAR = '**'; -/** - * Return true for static pattern. - */ -function isStaticPattern(pattern) { - return !isDynamicPattern(pattern); -} -exports.isStaticPattern = isStaticPattern; -/** - * Return true for pattern that looks like glob. - */ -function isDynamicPattern(pattern) { - return isGlob(pattern, { strict: false }); -} -exports.isDynamicPattern = isDynamicPattern; -/** - * Convert a windows «path» to a unix-style «path». - */ -function unixifyPattern(pattern) { - return pattern.replace(/\\/g, '/'); -} -exports.unixifyPattern = unixifyPattern; -/** - * Returns negative pattern as positive pattern. - */ -function convertToPositivePattern(pattern) { - return isNegativePattern(pattern) ? pattern.slice(1) : pattern; -} -exports.convertToPositivePattern = convertToPositivePattern; -/** - * Returns positive pattern as negative pattern. - */ -function convertToNegativePattern(pattern) { - return '!' + pattern; -} -exports.convertToNegativePattern = convertToNegativePattern; -/** - * Return true if provided pattern is negative pattern. - */ -function isNegativePattern(pattern) { - return pattern.startsWith('!') && pattern[1] !== '('; -} -exports.isNegativePattern = isNegativePattern; -/** - * Return true if provided pattern is positive pattern. - */ -function isPositivePattern(pattern) { - return !isNegativePattern(pattern); -} -exports.isPositivePattern = isPositivePattern; -/** - * Extracts negative patterns from array of patterns. - */ -function getNegativePatterns(patterns) { - return patterns.filter(isNegativePattern); -} -exports.getNegativePatterns = getNegativePatterns; -/** - * Extracts positive patterns from array of patterns. - */ -function getPositivePatterns(patterns) { - return patterns.filter(isPositivePattern); -} -exports.getPositivePatterns = getPositivePatterns; -/** - * Extract base directory from provided pattern. - */ -function getBaseDirectory(pattern) { - return globParent(pattern); -} -exports.getBaseDirectory = getBaseDirectory; -/** - * Return true if provided pattern has globstar. - */ -function hasGlobStar(pattern) { - return pattern.indexOf(GLOBSTAR) !== -1; -} -exports.hasGlobStar = hasGlobStar; -/** - * Return true if provided pattern ends with slash and globstar. - */ -function endsWithSlashGlobStar(pattern) { - return pattern.endsWith('/' + GLOBSTAR); -} -exports.endsWithSlashGlobStar = endsWithSlashGlobStar; -/** - * Returns «true» when pattern ends with a slash and globstar or the last partial of the pattern is static pattern. - */ -function isAffectDepthOfReadingPattern(pattern) { - var basename = path.basename(pattern); - return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); -} -exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; -/** - * Return naive depth of provided pattern without depth of the base directory. - */ -function getNaiveDepth(pattern) { - var base = getBaseDirectory(pattern); - var patternDepth = pattern.split('/').length; - var patternBaseDepth = base.split('/').length; - /** - * This is a hack for pattern that has no base directory. - * - * This is related to the `*\something\*` pattern. - */ - if (base === '.') { - return patternDepth - patternBaseDepth; - } - return patternDepth - patternBaseDepth - 1; -} -exports.getNaiveDepth = getNaiveDepth; -/** - * Return max naive depth of provided patterns without depth of the base directory. - */ -function getMaxNaivePatternsDepth(patterns) { - return patterns.reduce(function (max, pattern) { - var depth = getNaiveDepth(pattern); - return depth > max ? depth : max; - }, 0); -} -exports.getMaxNaivePatternsDepth = getMaxNaivePatternsDepth; -/** - * Make RegExp for provided pattern. - */ -function makeRe(pattern, options) { - return micromatch.makeRe(pattern, options); -} -exports.makeRe = makeRe; -/** - * Convert patterns to regexps. - */ -function convertPatternsToRe(patterns, options) { - return patterns.map(function (pattern) { return makeRe(pattern, options); }); -} -exports.convertPatternsToRe = convertPatternsToRe; -/** - * Returns true if the entry match any of the given RegExp's. - */ -function matchAny(entry, patternsRe) { - return patternsRe.some(function (patternRe) { return patternRe.test(entry); }); -} -exports.matchAny = matchAny; - - -/***/ }), -/* 580 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var util = __webpack_require__(112); -var braces = __webpack_require__(581); -var toRegex = __webpack_require__(582); -var extend = __webpack_require__(595); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(684); -var parsers = __webpack_require__(713); -var cache = __webpack_require__(714); -var utils = __webpack_require__(715); -var MAX_LENGTH = 1024 * 64; - -/** - * The main function takes a list of strings and one or more - * glob patterns to use for matching. - * - * ```js - * var mm = require('micromatch'); - * mm(list, patterns[, options]); - * - * console.log(mm(['a.js', 'a.txt'], ['*.js'])); - * //=> [ 'a.js' ] - * ``` - * @param {Array} `list` A list of strings to match - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of matches - * @summary false - * @api public - */ - -function micromatch(list, patterns, options) { - patterns = utils.arrayify(patterns); - list = utils.arrayify(list); - - var len = patterns.length; - if (list.length === 0 || len === 0) { - return []; - } - - if (len === 1) { - return micromatch.match(list, patterns[0], options); - } - - var omit = []; - var keep = []; - var idx = -1; - - while (++idx < len) { - var pattern = patterns[idx]; - - if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { - omit.push.apply(omit, micromatch.match(list, pattern.slice(1), options)); - } else { - keep.push.apply(keep, micromatch.match(list, pattern, options)); - } - } - - var matches = utils.diff(keep, omit); - if (!options || options.nodupes !== false) { - return utils.unique(matches); - } - - return matches; -} - -/** - * Similar to the main function, but `pattern` must be a string. - * - * ```js - * var mm = require('micromatch'); - * mm.match(list, pattern[, options]); - * - * console.log(mm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); - * //=> ['a.a', 'a.aa'] - * ``` - * @param {Array} `list` Array of strings to match - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of matches - * @api public - */ - -micromatch.match = function(list, pattern, options) { - if (Array.isArray(pattern)) { - throw new TypeError('expected pattern to be a string'); - } - - var unixify = utils.unixify(options); - var isMatch = memoize('match', pattern, options, micromatch.matcher); - var matches = []; - - list = utils.arrayify(list); - var len = list.length; - var idx = -1; - - while (++idx < len) { - var ele = list[idx]; - if (ele === pattern || isMatch(ele)) { - matches.push(utils.value(ele, unixify, options)); - } - } - - // if no options were passed, uniquify results and return - if (typeof options === 'undefined') { - return utils.unique(matches); - } - - if (matches.length === 0) { - if (options.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - if (options.nonull === true || options.nullglob === true) { - return [options.unescape ? utils.unescape(pattern) : pattern]; - } - } - - // if `opts.ignore` was defined, diff ignored list - if (options.ignore) { - matches = micromatch.not(matches, options.ignore, options); - } - - return options.nodupes !== false ? utils.unique(matches) : matches; -}; - -/** - * Returns true if the specified `string` matches the given glob `pattern`. - * - * ```js - * var mm = require('micromatch'); - * mm.isMatch(string, pattern[, options]); - * - * console.log(mm.isMatch('a.a', '*.a')); - * //=> true - * console.log(mm.isMatch('a.b', '*.a')); - * //=> false - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the string matches the glob pattern. - * @api public - */ - -micromatch.isMatch = function(str, pattern, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (isEmptyString(str) || isEmptyString(pattern)) { - return false; - } - - var equals = utils.equalsPattern(options); - if (equals(str)) { - return true; - } - - var isMatch = memoize('isMatch', pattern, options, micromatch.matcher); - return isMatch(str); -}; - -/** - * Returns true if some of the strings in the given `list` match any of the - * given glob `patterns`. - * - * ```js - * var mm = require('micromatch'); - * mm.some(list, patterns[, options]); - * - * console.log(mm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // true - * console.log(mm.some(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -micromatch.some = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - for (var i = 0; i < list.length; i++) { - if (micromatch(list[i], patterns, options).length === 1) { - return true; - } - } - return false; -}; - -/** - * Returns true if every string in the given `list` matches - * any of the given glob `patterns`. - * - * ```js - * var mm = require('micromatch'); - * mm.every(list, patterns[, options]); - * - * console.log(mm.every('foo.js', ['foo.js'])); - * // true - * console.log(mm.every(['foo.js', 'bar.js'], ['*.js'])); - * // true - * console.log(mm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // false - * console.log(mm.every(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -micromatch.every = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - for (var i = 0; i < list.length; i++) { - if (micromatch(list[i], patterns, options).length !== 1) { - return false; - } - } - return true; -}; - -/** - * Returns true if **any** of the given glob `patterns` - * match the specified `string`. - * - * ```js - * var mm = require('micromatch'); - * mm.any(string, patterns[, options]); - * - * console.log(mm.any('a.a', ['b.*', '*.a'])); - * //=> true - * console.log(mm.any('a.a', 'b.*')); - * //=> false - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -micromatch.any = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (isEmptyString(str) || isEmptyString(patterns)) { - return false; - } - - if (typeof patterns === 'string') { - patterns = [patterns]; - } - - for (var i = 0; i < patterns.length; i++) { - if (micromatch.isMatch(str, patterns[i], options)) { - return true; - } - } - return false; -}; - -/** - * Returns true if **all** of the given `patterns` match - * the specified string. - * - * ```js - * var mm = require('micromatch'); - * mm.all(string, patterns[, options]); - * - * console.log(mm.all('foo.js', ['foo.js'])); - * // true - * - * console.log(mm.all('foo.js', ['*.js', '!foo.js'])); - * // false - * - * console.log(mm.all('foo.js', ['*.js', 'foo.js'])); - * // true - * - * console.log(mm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); - * // true - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -micromatch.all = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - if (typeof patterns === 'string') { - patterns = [patterns]; - } - for (var i = 0; i < patterns.length; i++) { - if (!micromatch.isMatch(str, patterns[i], options)) { - return false; - } - } - return true; -}; - -/** - * Returns a list of strings that _**do not match any**_ of the given `patterns`. - * - * ```js - * var mm = require('micromatch'); - * mm.not(list, patterns[, options]); - * - * console.log(mm.not(['a.a', 'b.b', 'c.c'], '*.a')); - * //=> ['b.b', 'c.c'] - * ``` - * @param {Array} `list` Array of strings to match. - * @param {String|Array} `patterns` One or more glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of strings that **do not match** the given patterns. - * @api public - */ - -micromatch.not = function(list, patterns, options) { - var opts = extend({}, options); - var ignore = opts.ignore; - delete opts.ignore; - - var unixify = utils.unixify(opts); - list = utils.arrayify(list).map(unixify); - - var matches = utils.diff(list, micromatch(list, patterns, opts)); - if (ignore) { - matches = utils.diff(matches, micromatch(list, ignore)); - } - - return opts.nodupes !== false ? utils.unique(matches) : matches; -}; - -/** - * Returns true if the given `string` contains the given pattern. Similar - * to [.isMatch](#isMatch) but the pattern can match any part of the string. - * - * ```js - * var mm = require('micromatch'); - * mm.contains(string, pattern[, options]); - * - * console.log(mm.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(mm.contains('aa/bb/cc', '*d')); - * //=> false - * ``` - * @param {String} `str` The string to match. - * @param {String|Array} `patterns` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the patter matches any part of `str`. - * @api public - */ - -micromatch.contains = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (typeof patterns === 'string') { - if (isEmptyString(str) || isEmptyString(patterns)) { - return false; - } - - var equals = utils.equalsPattern(patterns, options); - if (equals(str)) { - return true; - } - var contains = utils.containsPattern(patterns, options); - if (contains(str)) { - return true; - } - } - - var opts = extend({}, options, {contains: true}); - return micromatch.any(str, patterns, opts); -}; - -/** - * Returns true if the given pattern and options should enable - * the `matchBase` option. - * @return {Boolean} - * @api private - */ - -micromatch.matchBase = function(pattern, options) { - if (pattern && pattern.indexOf('/') !== -1 || !options) return false; - return options.basename === true || options.matchBase === true; -}; - -/** - * Filter the keys of the given object with the given `glob` pattern - * and `options`. Does not attempt to match nested keys. If you need this feature, - * use [glob-object][] instead. - * - * ```js - * var mm = require('micromatch'); - * mm.matchKeys(object, patterns[, options]); - * - * var obj = { aa: 'a', ab: 'b', ac: 'c' }; - * console.log(mm.matchKeys(obj, '*b')); - * //=> { ab: 'b' } - * ``` - * @param {Object} `object` The object with keys to filter. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Object} Returns an object with only keys that match the given patterns. - * @api public - */ - -micromatch.matchKeys = function(obj, patterns, options) { - if (!utils.isObject(obj)) { - throw new TypeError('expected the first argument to be an object'); - } - var keys = micromatch(Object.keys(obj), patterns, options); - return utils.pick(obj, keys); -}; - -/** - * Returns a memoized matcher function from the given glob `pattern` and `options`. - * The returned function takes a string to match as its only argument and returns - * true if the string is a match. - * - * ```js - * var mm = require('micromatch'); - * mm.matcher(pattern[, options]); - * - * var isMatch = mm.matcher('*.!(*a)'); - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.b')); - * //=> true - * ``` - * @param {String} `pattern` Glob pattern - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {Function} Returns a matcher function. - * @api public - */ - -micromatch.matcher = function matcher(pattern, options) { - if (Array.isArray(pattern)) { - return compose(pattern, options, matcher); - } - - // if pattern is a regex - if (pattern instanceof RegExp) { - return test(pattern); - } - - // if pattern is invalid - if (!utils.isString(pattern)) { - throw new TypeError('expected pattern to be an array, string or regex'); - } - - // if pattern is a non-glob string - if (!utils.hasSpecialChars(pattern)) { - if (options && options.nocase === true) { - pattern = pattern.toLowerCase(); - } - return utils.matchPath(pattern, options); - } - - // if pattern is a glob string - var re = micromatch.makeRe(pattern, options); - - // if `options.matchBase` or `options.basename` is defined - if (micromatch.matchBase(pattern, options)) { - return utils.matchBasename(re, options); - } - - function test(regex) { - var equals = utils.equalsPattern(options); - var unixify = utils.unixify(options); - - return function(str) { - if (equals(str)) { - return true; - } - - if (regex.test(unixify(str))) { - return true; - } - return false; - }; - } - - var fn = test(re); - Object.defineProperty(fn, 'result', { - configurable: true, - enumerable: false, - value: re.result - }); - return fn; -}; - -/** - * Returns an array of matches captured by `pattern` in `string, or `null` if the pattern did not match. - * - * ```js - * var mm = require('micromatch'); - * mm.capture(pattern, string[, options]); - * - * console.log(mm.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(mm.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `pattern` Glob pattern to use for matching. - * @param {String} `string` String to match - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns an array of captures if the string matches the glob pattern, otherwise `null`. - * @api public - */ - -micromatch.capture = function(pattern, str, options) { - var re = micromatch.makeRe(pattern, extend({capture: true}, options)); - var unixify = utils.unixify(options); - - function match() { - return function(string) { - var match = re.exec(unixify(string)); - if (!match) { - return null; - } - - return match.slice(1); - }; - } - - var capture = memoize('capture', pattern, options, match); - return capture(str); -}; - -/** - * Create a regular expression from the given glob `pattern`. - * - * ```js - * var mm = require('micromatch'); - * mm.makeRe(pattern[, options]); - * - * console.log(mm.makeRe('*.js')); - * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ - * ``` - * @param {String} `pattern` A glob pattern to convert to regex. - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {RegExp} Returns a regex created from the given pattern. - * @api public - */ - -micromatch.makeRe = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - function makeRe() { - var result = micromatch.create(pattern, options); - var ast_array = []; - var output = result.map(function(obj) { - obj.ast.state = obj.state; - ast_array.push(obj.ast); - return obj.output; - }); - - var regex = toRegex(output.join('|'), options); - Object.defineProperty(regex, 'result', { - configurable: true, - enumerable: false, - value: ast_array - }); - return regex; - } - - return memoize('makeRe', pattern, options, makeRe); -}; - -/** - * Expand the given brace `pattern`. - * - * ```js - * var mm = require('micromatch'); - * console.log(mm.braces('foo/{a,b}/bar')); - * //=> ['foo/(a|b)/bar'] - * - * console.log(mm.braces('foo/{a,b}/bar', {expand: true})); - * //=> ['foo/(a|b)/bar'] - * ``` - * @param {String} `pattern` String with brace pattern to expand. - * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options. - * @return {Array} - * @api public - */ - -micromatch.braces = function(pattern, options) { - if (typeof pattern !== 'string' && !Array.isArray(pattern)) { - throw new TypeError('expected pattern to be an array or string'); - } - - function expand() { - if (options && options.nobrace === true || !/\{.*\}/.test(pattern)) { - return utils.arrayify(pattern); - } - return braces(pattern, options); - } - - return memoize('braces', pattern, options, expand); -}; - -/** - * Proxy to the [micromatch.braces](#method), for parity with - * minimatch. - */ - -micromatch.braceExpand = function(pattern, options) { - var opts = extend({}, options, {expand: true}); - return micromatch.braces(pattern, opts); -}; - -/** - * Parses the given glob `pattern` and returns an array of abstract syntax - * trees (ASTs), with the compiled `output` and optional source `map` on - * each AST. - * - * ```js - * var mm = require('micromatch'); - * mm.create(pattern[, options]); - * - * console.log(mm.create('abc/*.js')); - * // [{ options: { source: 'string', sourcemap: true }, - * // state: {}, - * // compilers: - * // { ... }, - * // output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: - * // [ ... ], - * // dot: false, - * // input: 'abc/*.js' }, - * // parsingErrors: [], - * // map: - * // { version: 3, - * // sources: [ 'string' ], - * // names: [], - * // mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE', - * // sourcesContent: [ 'abc/*.js' ] }, - * // position: { line: 1, column: 28 }, - * // content: {}, - * // files: {}, - * // idx: 6 }] - * ``` - * @param {String} `pattern` Glob pattern to parse and compile. - * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed. - * @return {Object} Returns an object with the parsed AST, compiled string and optional source map. - * @api public - */ - -micromatch.create = function(pattern, options) { - return memoize('create', pattern, options, function() { - function create(str, opts) { - return micromatch.compile(micromatch.parse(str, opts), opts); - } - - pattern = micromatch.braces(pattern, options); - var len = pattern.length; - var idx = -1; - var res = []; - - while (++idx < len) { - res.push(create(pattern[idx], options)); - } - return res; - }); -}; - -/** - * Parse the given `str` with the given `options`. - * - * ```js - * var mm = require('micromatch'); - * mm.parse(pattern[, options]); - * - * var ast = mm.parse('a/{b,c}/d'); - * console.log(ast); - * // { type: 'root', - * // errors: [], - * // input: 'a/{b,c}/d', - * // nodes: - * // [ { type: 'bos', val: '' }, - * // { type: 'text', val: 'a/' }, - * // { type: 'brace', - * // nodes: - * // [ { type: 'brace.open', val: '{' }, - * // { type: 'text', val: 'b,c' }, - * // { type: 'brace.close', val: '}' } ] }, - * // { type: 'text', val: '/d' }, - * // { type: 'eos', val: '' } ] } - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {Object} Returns an AST - * @api public - */ - -micromatch.parse = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - function parse() { - var snapdragon = utils.instantiate(null, options); - parsers(snapdragon, options); - - var ast = snapdragon.parse(pattern, options); - utils.define(ast, 'snapdragon', snapdragon); - ast.input = pattern; - return ast; - } - - return memoize('parse', pattern, options, parse); -}; - -/** - * Compile the given `ast` or string with the given `options`. - * - * ```js - * var mm = require('micromatch'); - * mm.compile(ast[, options]); - * - * var ast = mm.parse('a/{b,c}/d'); - * console.log(mm.compile(ast)); - * // { options: { source: 'string' }, - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // brace: [Function], - * // 'brace.open': [Function], - * // text: [Function], - * // 'brace.close': [Function] }, - * // output: [ 'a/(b|c)/d' ], - * // ast: - * // { ... }, - * // parsingErrors: [] } - * ``` - * @param {Object|String} `ast` - * @param {Object} `options` - * @return {Object} Returns an object that has an `output` property with the compiled string. - * @api public - */ - -micromatch.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = micromatch.parse(ast, options); - } - - return memoize('compile', ast.input, options, function() { - var snapdragon = utils.instantiate(ast, options); - compilers(snapdragon, options); - return snapdragon.compile(ast, options); - }); -}; - -/** - * Clear the regex cache. - * - * ```js - * mm.clearCache(); - * ``` - * @api public - */ - -micromatch.clearCache = function() { - micromatch.cache.caches = {}; -}; - -/** - * Returns true if the given value is effectively an empty string - */ - -function isEmptyString(val) { - return String(val) === '' || String(val) === './'; -} - -/** - * Compose a matcher function with the given patterns. - * This allows matcher functions to be compiled once and - * called multiple times. - */ - -function compose(patterns, options, matcher) { - var matchers; - - return memoize('compose', String(patterns), options, function() { - return function(file) { - // delay composition until it's invoked the first time, - // after that it won't be called again - if (!matchers) { - matchers = []; - for (var i = 0; i < patterns.length; i++) { - matchers.push(matcher(patterns[i], options)); - } - } - - var len = matchers.length; - while (len--) { - if (matchers[len](file) === true) { - return true; - } - } - return false; - }; - }); -} - -/** - * Memoize a generated regex or function. A unique key is generated - * from the `type` (usually method name), the `pattern`, and - * user-defined options. - */ - -function memoize(type, pattern, options, fn) { - var key = utils.createKey(type + '=' + pattern, options); - - if (options && options.cache === false) { - return fn(pattern, options); - } - - if (cache.has(type, key)) { - return cache.get(type, key); - } - - var val = fn(pattern, options); - cache.set(type, key, val); - return val; -} - -/** - * Expose compiler, parser and cache on `micromatch` - */ - -micromatch.compilers = compilers; -micromatch.parsers = parsers; -micromatch.caches = cache.caches; - -/** - * Expose `micromatch` - * @type {Function} - */ - -module.exports = micromatch; - - -/***/ }), -/* 581 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var toRegex = __webpack_require__(582); -var unique = __webpack_require__(600); -var extend = __webpack_require__(601); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(603); -var parsers = __webpack_require__(613); -var Braces = __webpack_require__(617); -var utils = __webpack_require__(604); -var MAX_LENGTH = 1024 * 64; -var cache = {}; - -/** - * Convert the given `braces` pattern into a regex-compatible string. By default, only one string is generated for every input string. Set `options.expand` to true to return an array of patterns (similar to Bash or minimatch. Before using `options.expand`, it's recommended that you read the [performance notes](#performance)). - * - * ```js - * var braces = require('braces'); - * console.log(braces('{a,b,c}')); - * //=> ['(a|b|c)'] - * - * console.log(braces('{a,b,c}', {expand: true})); - * //=> ['a', 'b', 'c'] - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {String} - * @api public - */ - -function braces(pattern, options) { - var key = utils.createKey(String(pattern), options); - var arr = []; - - var disabled = options && options.cache === false; - if (!disabled && cache.hasOwnProperty(key)) { - return cache[key]; - } - - if (Array.isArray(pattern)) { - for (var i = 0; i < pattern.length; i++) { - arr.push.apply(arr, braces.create(pattern[i], options)); - } - } else { - arr = braces.create(pattern, options); - } - - if (options && options.nodupes === true) { - arr = unique(arr); - } - - if (!disabled) { - cache[key] = arr; - } - return arr; -} - -/** - * Expands a brace pattern into an array. This method is called by the main [braces](#braces) function when `options.expand` is true. Before using this method it's recommended that you read the [performance notes](#performance)) and advantages of using [.optimize](#optimize) instead. - * - * ```js - * var braces = require('braces'); - * console.log(braces.expand('a/{b,c}/d')); - * //=> ['a/b/d', 'a/c/d']; - * ``` - * @param {String} `pattern` Brace pattern - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ - -braces.expand = function(pattern, options) { - return braces.create(pattern, extend({}, options, {expand: true})); -}; - -/** - * Expands a brace pattern into a regex-compatible, optimized string. This method is called by the main [braces](#braces) function by default. - * - * ```js - * var braces = require('braces'); - * console.log(braces.expand('a/{b,c}/d')); - * //=> ['a/(b|c)/d'] - * ``` - * @param {String} `pattern` Brace pattern - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ - -braces.optimize = function(pattern, options) { - return braces.create(pattern, options); -}; - -/** - * Processes a brace pattern and returns either an expanded array (if `options.expand` is true), a highly optimized regex-compatible string. This method is called by the main [braces](#braces) function. - * - * ```js - * var braces = require('braces'); - * console.log(braces.create('user-{200..300}/project-{a,b,c}-{1..10}')) - * //=> 'user-(20[0-9]|2[1-9][0-9]|300)/project-(a|b|c)-([1-9]|10)' - * ``` - * @param {String} `pattern` Brace pattern - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ - -braces.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - var maxLength = (options && options.maxLength) || MAX_LENGTH; - if (pattern.length >= maxLength) { - throw new Error('expected pattern to be less than ' + maxLength + ' characters'); - } - - function create() { - if (pattern === '' || pattern.length < 3) { - return [pattern]; - } - - if (utils.isEmptySets(pattern)) { - return []; - } - - if (utils.isQuotedString(pattern)) { - return [pattern.slice(1, -1)]; - } - - var proto = new Braces(options); - var result = !options || options.expand !== true - ? proto.optimize(pattern, options) - : proto.expand(pattern, options); - - // get the generated pattern(s) - var arr = result.output; - - // filter out empty strings if specified - if (options && options.noempty === true) { - arr = arr.filter(Boolean); - } - - // filter out duplicates if specified - if (options && options.nodupes === true) { - arr = unique(arr); - } - - Object.defineProperty(arr, 'result', { - enumerable: false, - value: result - }); - - return arr; - } - - return memoize('create', pattern, options, create); -}; - -/** - * Create a regular expression from the given string `pattern`. - * - * ```js - * var braces = require('braces'); - * - * console.log(braces.makeRe('id-{200..300}')); - * //=> /^(?:id-(20[0-9]|2[1-9][0-9]|300))$/ - * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -braces.makeRe = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - var maxLength = (options && options.maxLength) || MAX_LENGTH; - if (pattern.length >= maxLength) { - throw new Error('expected pattern to be less than ' + maxLength + ' characters'); - } - - function makeRe() { - var arr = braces(pattern, options); - var opts = extend({strictErrors: false}, options); - return toRegex(arr, opts); - } - - return memoize('makeRe', pattern, options, makeRe); -}; - -/** - * Parse the given `str` with the given `options`. - * - * ```js - * var braces = require('braces'); - * var ast = braces.parse('a/{b,c}/d'); - * console.log(ast); - * // { type: 'root', - * // errors: [], - * // input: 'a/{b,c}/d', - * // nodes: - * // [ { type: 'bos', val: '' }, - * // { type: 'text', val: 'a/' }, - * // { type: 'brace', - * // nodes: - * // [ { type: 'brace.open', val: '{' }, - * // { type: 'text', val: 'b,c' }, - * // { type: 'brace.close', val: '}' } ] }, - * // { type: 'text', val: '/d' }, - * // { type: 'eos', val: '' } ] } - * ``` - * @param {String} `pattern` Brace pattern to parse - * @param {Object} `options` - * @return {Object} Returns an AST - * @api public - */ - -braces.parse = function(pattern, options) { - var proto = new Braces(options); - return proto.parse(pattern, options); -}; - -/** - * Compile the given `ast` or string with the given `options`. - * - * ```js - * var braces = require('braces'); - * var ast = braces.parse('a/{b,c}/d'); - * console.log(braces.compile(ast)); - * // { options: { source: 'string' }, - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // brace: [Function], - * // 'brace.open': [Function], - * // text: [Function], - * // 'brace.close': [Function] }, - * // output: [ 'a/(b|c)/d' ], - * // ast: - * // { ... }, - * // parsingErrors: [] } - * ``` - * @param {Object|String} `ast` AST from [.parse](#parse). If a string is passed it will be parsed first. - * @param {Object} `options` - * @return {Object} Returns an object that has an `output` property with the compiled string. - * @api public - */ - -braces.compile = function(ast, options) { - var proto = new Braces(options); - return proto.compile(ast, options); -}; - -/** - * Clear the regex cache. - * - * ```js - * braces.clearCache(); - * ``` - * @api public - */ - -braces.clearCache = function() { - cache = braces.cache = {}; -}; - -/** - * Memoize a generated regex or function. A unique key is generated - * from the method name, pattern, and user-defined options. Set - * options.memoize to false to disable. - */ - -function memoize(type, pattern, options, fn) { - var key = utils.createKey(type + ':' + pattern, options); - var disabled = options && options.cache === false; - if (disabled) { - braces.clearCache(); - return fn(pattern, options); - } - - if (cache.hasOwnProperty(key)) { - return cache[key]; - } - - var res = fn(pattern, options); - cache[key] = res; - return res; -} - -/** - * Expose `Braces` constructor and methods - * @type {Function} - */ - -braces.Braces = Braces; -braces.compilers = compilers; -braces.parsers = parsers; -braces.cache = cache; - -/** - * Expose `braces` - * @type {Function} - */ - -module.exports = braces; - - -/***/ }), -/* 582 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var safe = __webpack_require__(583); -var define = __webpack_require__(589); -var extend = __webpack_require__(595); -var not = __webpack_require__(599); -var MAX_LENGTH = 1024 * 64; - -/** - * Session cache - */ - -var cache = {}; - -/** - * Create a regular expression from the given `pattern` string. - * - * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -module.exports = function(patterns, options) { - if (!Array.isArray(patterns)) { - return makeRe(patterns, options); - } - return makeRe(patterns.join('|'), options); -}; - -/** - * Create a regular expression from the given `pattern` string. - * - * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -function makeRe(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - var key = pattern; - // do this before shallow cloning options, it's a lot faster - if (!options || (options && options.cache !== false)) { - key = createKey(pattern, options); - - if (cache.hasOwnProperty(key)) { - return cache[key]; - } - } - - var opts = extend({}, options); - if (opts.contains === true) { - if (opts.negate === true) { - opts.strictNegate = false; - } else { - opts.strict = false; - } - } - - if (opts.strict === false) { - opts.strictOpen = false; - opts.strictClose = false; - } - - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var flags = opts.flags || ''; - var regex; - - if (opts.nocase === true && !/i/.test(flags)) { - flags += 'i'; - } - - try { - if (opts.negate || typeof opts.strictNegate === 'boolean') { - pattern = not.create(pattern, opts); - } - - var str = open + '(?:' + pattern + ')' + close; - regex = new RegExp(str, flags); - - if (opts.safe === true && safe(regex) === false) { - throw new Error('potentially unsafe regular expression: ' + regex.source); - } - - } catch (err) { - if (opts.strictErrors === true || opts.safe === true) { - err.key = key; - err.pattern = pattern; - err.originalOptions = options; - err.createdOptions = opts; - throw err; - } - - try { - regex = new RegExp('^' + pattern.replace(/(\W)/g, '\\$1') + '$'); - } catch (err) { - regex = /.^/; //<= match nothing - } - } - - if (opts.cache !== false) { - memoize(regex, key, pattern, opts); - } - return regex; -} - -/** - * Memoize generated regex. This can result in dramatic speed improvements - * and simplify debugging by adding options and pattern to the regex. It can be - * disabled by passing setting `options.cache` to false. - */ - -function memoize(regex, key, pattern, options) { - define(regex, 'cached', true); - define(regex, 'pattern', pattern); - define(regex, 'options', options); - define(regex, 'key', key); - cache[key] = regex; -} - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -function createKey(pattern, options) { - if (!options) return pattern; - var key = pattern; - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); - } - } - return key; -} - -/** - * Expose `makeRe` - */ - -module.exports.makeRe = makeRe; - - -/***/ }), -/* 583 */ -/***/ (function(module, exports, __webpack_require__) { - -var parse = __webpack_require__(584); -var types = parse.types; - -module.exports = function (re, opts) { - if (!opts) opts = {}; - var replimit = opts.limit === undefined ? 25 : opts.limit; - - if (isRegExp(re)) re = re.source; - else if (typeof re !== 'string') re = String(re); - - try { re = parse(re) } - catch (err) { return false } - - var reps = 0; - return (function walk (node, starHeight) { - if (node.type === types.REPETITION) { - starHeight ++; - reps ++; - if (starHeight > 1) return false; - if (reps > replimit) return false; - } - - if (node.options) { - for (var i = 0, len = node.options.length; i < len; i++) { - var ok = walk({ stack: node.options[i] }, starHeight); - if (!ok) return false; - } - } - var stack = node.stack || (node.value && node.value.stack); - if (!stack) return true; - - for (var i = 0; i < stack.length; i++) { - var ok = walk(stack[i], starHeight); - if (!ok) return false; - } - - return true; - })(re, 0); -}; - -function isRegExp (x) { - return {}.toString.call(x) === '[object RegExp]'; -} - - -/***/ }), -/* 584 */ -/***/ (function(module, exports, __webpack_require__) { - -var util = __webpack_require__(585); -var types = __webpack_require__(586); -var sets = __webpack_require__(587); -var positions = __webpack_require__(588); - - -module.exports = function(regexpStr) { - var i = 0, l, c, - start = { type: types.ROOT, stack: []}, - - // Keep track of last clause/group and stack. - lastGroup = start, - last = start.stack, - groupStack = []; - - - var repeatErr = function(i) { - util.error(regexpStr, 'Nothing to repeat at column ' + (i - 1)); - }; - - // Decode a few escaped characters. - var str = util.strToChars(regexpStr); - l = str.length; - - // Iterate through each character in string. - while (i < l) { - c = str[i++]; - - switch (c) { - // Handle escaped characters, inclues a few sets. - case '\\': - c = str[i++]; - - switch (c) { - case 'b': - last.push(positions.wordBoundary()); - break; - - case 'B': - last.push(positions.nonWordBoundary()); - break; - - case 'w': - last.push(sets.words()); - break; - - case 'W': - last.push(sets.notWords()); - break; - - case 'd': - last.push(sets.ints()); - break; - - case 'D': - last.push(sets.notInts()); - break; - - case 's': - last.push(sets.whitespace()); - break; - - case 'S': - last.push(sets.notWhitespace()); - break; - - default: - // Check if c is integer. - // In which case it's a reference. - if (/\d/.test(c)) { - last.push({ type: types.REFERENCE, value: parseInt(c, 10) }); - - // Escaped character. - } else { - last.push({ type: types.CHAR, value: c.charCodeAt(0) }); - } - } - - break; - - - // Positionals. - case '^': - last.push(positions.begin()); - break; - - case '$': - last.push(positions.end()); - break; - - - // Handle custom sets. - case '[': - // Check if this class is 'anti' i.e. [^abc]. - var not; - if (str[i] === '^') { - not = true; - i++; - } else { - not = false; - } - - // Get all the characters in class. - var classTokens = util.tokenizeClass(str.slice(i), regexpStr); - - // Increase index by length of class. - i += classTokens[1]; - last.push({ - type: types.SET, - set: classTokens[0], - not: not, - }); - - break; - - - // Class of any character except \n. - case '.': - last.push(sets.anyChar()); - break; - - - // Push group onto stack. - case '(': - // Create group. - var group = { - type: types.GROUP, - stack: [], - remember: true, - }; - - c = str[i]; - - // If if this is a special kind of group. - if (c === '?') { - c = str[i + 1]; - i += 2; - - // Match if followed by. - if (c === '=') { - group.followedBy = true; - - // Match if not followed by. - } else if (c === '!') { - group.notFollowedBy = true; - - } else if (c !== ':') { - util.error(regexpStr, - 'Invalid group, character \'' + c + - '\' after \'?\' at column ' + (i - 1)); - } - - group.remember = false; - } - - // Insert subgroup into current group stack. - last.push(group); - - // Remember the current group for when the group closes. - groupStack.push(lastGroup); - - // Make this new group the current group. - lastGroup = group; - last = group.stack; - break; - - - // Pop group out of stack. - case ')': - if (groupStack.length === 0) { - util.error(regexpStr, 'Unmatched ) at column ' + (i - 1)); - } - lastGroup = groupStack.pop(); - - // Check if this group has a PIPE. - // To get back the correct last stack. - last = lastGroup.options ? - lastGroup.options[lastGroup.options.length - 1] : lastGroup.stack; - break; - - - // Use pipe character to give more choices. - case '|': - // Create array where options are if this is the first PIPE - // in this clause. - if (!lastGroup.options) { - lastGroup.options = [lastGroup.stack]; - delete lastGroup.stack; - } - - // Create a new stack and add to options for rest of clause. - var stack = []; - lastGroup.options.push(stack); - last = stack; - break; - - - // Repetition. - // For every repetition, remove last element from last stack - // then insert back a RANGE object. - // This design is chosen because there could be more than - // one repetition symbols in a regex i.e. `a?+{2,3}`. - case '{': - var rs = /^(\d+)(,(\d+)?)?\}/.exec(str.slice(i)), min, max; - if (rs !== null) { - if (last.length === 0) { - repeatErr(i); - } - min = parseInt(rs[1], 10); - max = rs[2] ? rs[3] ? parseInt(rs[3], 10) : Infinity : min; - i += rs[0].length; - - last.push({ - type: types.REPETITION, - min: min, - max: max, - value: last.pop(), - }); - } else { - last.push({ - type: types.CHAR, - value: 123, - }); - } - break; - - case '?': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 0, - max: 1, - value: last.pop(), - }); - break; - - case '+': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 1, - max: Infinity, - value: last.pop(), - }); - break; - - case '*': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 0, - max: Infinity, - value: last.pop(), - }); - break; - - - // Default is a character that is not `\[](){}?+*^$`. - default: - last.push({ - type: types.CHAR, - value: c.charCodeAt(0), - }); - } - - } - - // Check if any groups have not been closed. - if (groupStack.length !== 0) { - util.error(regexpStr, 'Unterminated group'); - } - - return start; -}; - -module.exports.types = types; - - -/***/ }), -/* 585 */ -/***/ (function(module, exports, __webpack_require__) { - -var types = __webpack_require__(586); -var sets = __webpack_require__(587); - - -// All of these are private and only used by randexp. -// It's assumed that they will always be called with the correct input. - -var CTRL = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ ?'; -var SLSH = { '0': 0, 't': 9, 'n': 10, 'v': 11, 'f': 12, 'r': 13 }; - -/** - * Finds character representations in str and convert all to - * their respective characters - * - * @param {String} str - * @return {String} - */ -exports.strToChars = function(str) { - /* jshint maxlen: false */ - var chars_regex = /(\[\\b\])|(\\)?\\(?:u([A-F0-9]{4})|x([A-F0-9]{2})|(0?[0-7]{2})|c([@A-Z\[\\\]\^?])|([0tnvfr]))/g; - str = str.replace(chars_regex, function(s, b, lbs, a16, b16, c8, dctrl, eslsh) { - if (lbs) { - return s; - } - - var code = b ? 8 : - a16 ? parseInt(a16, 16) : - b16 ? parseInt(b16, 16) : - c8 ? parseInt(c8, 8) : - dctrl ? CTRL.indexOf(dctrl) : - SLSH[eslsh]; - - var c = String.fromCharCode(code); - - // Escape special regex characters. - if (/[\[\]{}\^$.|?*+()]/.test(c)) { - c = '\\' + c; - } - - return c; - }); - - return str; -}; - - -/** - * turns class into tokens - * reads str until it encounters a ] not preceeded by a \ - * - * @param {String} str - * @param {String} regexpStr - * @return {Array., Number>} - */ -exports.tokenizeClass = function(str, regexpStr) { - /* jshint maxlen: false */ - var tokens = []; - var regexp = /\\(?:(w)|(d)|(s)|(W)|(D)|(S))|((?:(?:\\)(.)|([^\]\\]))-(?:\\)?([^\]]))|(\])|(?:\\)?(.)/g; - var rs, c; - - - while ((rs = regexp.exec(str)) != null) { - if (rs[1]) { - tokens.push(sets.words()); - - } else if (rs[2]) { - tokens.push(sets.ints()); - - } else if (rs[3]) { - tokens.push(sets.whitespace()); - - } else if (rs[4]) { - tokens.push(sets.notWords()); - - } else if (rs[5]) { - tokens.push(sets.notInts()); - - } else if (rs[6]) { - tokens.push(sets.notWhitespace()); - - } else if (rs[7]) { - tokens.push({ - type: types.RANGE, - from: (rs[8] || rs[9]).charCodeAt(0), - to: rs[10].charCodeAt(0), - }); - - } else if (c = rs[12]) { - tokens.push({ - type: types.CHAR, - value: c.charCodeAt(0), - }); - - } else { - return [tokens, regexp.lastIndex]; - } - } - - exports.error(regexpStr, 'Unterminated character class'); -}; - - -/** - * Shortcut to throw errors. - * - * @param {String} regexp - * @param {String} msg - */ -exports.error = function(regexp, msg) { - throw new SyntaxError('Invalid regular expression: /' + regexp + '/: ' + msg); -}; - - -/***/ }), -/* 586 */ -/***/ (function(module, exports) { - -module.exports = { - ROOT : 0, - GROUP : 1, - POSITION : 2, - SET : 3, - RANGE : 4, - REPETITION : 5, - REFERENCE : 6, - CHAR : 7, -}; - - -/***/ }), -/* 587 */ -/***/ (function(module, exports, __webpack_require__) { - -var types = __webpack_require__(586); - -var INTS = function() { - return [{ type: types.RANGE , from: 48, to: 57 }]; -}; - -var WORDS = function() { - return [ - { type: types.CHAR, value: 95 }, - { type: types.RANGE, from: 97, to: 122 }, - { type: types.RANGE, from: 65, to: 90 } - ].concat(INTS()); -}; - -var WHITESPACE = function() { - return [ - { type: types.CHAR, value: 9 }, - { type: types.CHAR, value: 10 }, - { type: types.CHAR, value: 11 }, - { type: types.CHAR, value: 12 }, - { type: types.CHAR, value: 13 }, - { type: types.CHAR, value: 32 }, - { type: types.CHAR, value: 160 }, - { type: types.CHAR, value: 5760 }, - { type: types.CHAR, value: 6158 }, - { type: types.CHAR, value: 8192 }, - { type: types.CHAR, value: 8193 }, - { type: types.CHAR, value: 8194 }, - { type: types.CHAR, value: 8195 }, - { type: types.CHAR, value: 8196 }, - { type: types.CHAR, value: 8197 }, - { type: types.CHAR, value: 8198 }, - { type: types.CHAR, value: 8199 }, - { type: types.CHAR, value: 8200 }, - { type: types.CHAR, value: 8201 }, - { type: types.CHAR, value: 8202 }, - { type: types.CHAR, value: 8232 }, - { type: types.CHAR, value: 8233 }, - { type: types.CHAR, value: 8239 }, - { type: types.CHAR, value: 8287 }, - { type: types.CHAR, value: 12288 }, - { type: types.CHAR, value: 65279 } - ]; -}; - -var NOTANYCHAR = function() { - return [ - { type: types.CHAR, value: 10 }, - { type: types.CHAR, value: 13 }, - { type: types.CHAR, value: 8232 }, - { type: types.CHAR, value: 8233 }, - ]; -}; - -// Predefined class objects. -exports.words = function() { - return { type: types.SET, set: WORDS(), not: false }; -}; - -exports.notWords = function() { - return { type: types.SET, set: WORDS(), not: true }; -}; - -exports.ints = function() { - return { type: types.SET, set: INTS(), not: false }; -}; - -exports.notInts = function() { - return { type: types.SET, set: INTS(), not: true }; -}; - -exports.whitespace = function() { - return { type: types.SET, set: WHITESPACE(), not: false }; -}; - -exports.notWhitespace = function() { - return { type: types.SET, set: WHITESPACE(), not: true }; -}; - -exports.anyChar = function() { - return { type: types.SET, set: NOTANYCHAR(), not: true }; -}; - - -/***/ }), -/* 588 */ -/***/ (function(module, exports, __webpack_require__) { - -var types = __webpack_require__(586); - -exports.wordBoundary = function() { - return { type: types.POSITION, value: 'b' }; -}; - -exports.nonWordBoundary = function() { - return { type: types.POSITION, value: 'B' }; -}; - -exports.begin = function() { - return { type: types.POSITION, value: '^' }; -}; - -exports.end = function() { - return { type: types.POSITION, value: '$' }; -}; - - -/***/ }), -/* 589 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isobject = __webpack_require__(590); -var isDescriptor = __webpack_require__(591); -var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) - ? Reflect.defineProperty - : Object.defineProperty; - -module.exports = function defineProperty(obj, key, val) { - if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { - throw new TypeError('expected an object, function, or array'); - } - - if (typeof key !== 'string') { - throw new TypeError('expected "key" to be a string'); - } - - if (isDescriptor(val)) { - define(obj, key, val); - return obj; - } - - define(obj, key, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); - - return obj; -}; - - -/***/ }), -/* 590 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * isobject - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function isObject(val) { - return val != null && typeof val === 'object' && Array.isArray(val) === false; -}; - - -/***/ }), -/* 591 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); -var isAccessor = __webpack_require__(593); -var isData = __webpack_require__(594); - -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; - - -/***/ }), -/* 592 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } - - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; - - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; - - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; - - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } - - if (isGeneratorObj(val)) { - return 'generator'; - } - - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } - - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; - -function ctorName(val) { - return typeof val.constructor === 'function' ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} - -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} - -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} - -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} - -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} - -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} - -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } - } - return false; -} - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ - -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; -} - - -/***/ }), -/* 593 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; - -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (typeOf(obj) !== 'object') { - return false; - } - - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } - - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } - - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } - - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === accessor[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} - -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} - -/** - * Expose `isAccessorDescriptor` - */ - -module.exports = isAccessorDescriptor; - - -/***/ }), -/* 594 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-data-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); - -module.exports = function isDataDescriptor(obj, prop) { - // data descriptor properties - var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' - }; - - if (typeOf(obj) !== 'object') { - return false; - } - - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (!('value' in obj) && !('writable' in obj)) { - return false; - } - - for (var key in obj) { - if (key === 'value') continue; - - if (!data.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === data[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -}; - - -/***/ }), -/* 595 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(596); -var assignSymbols = __webpack_require__(598); - -module.exports = Object.assign || function(obj/*, objects*/) { - if (obj === null || typeof obj === 'undefined') { - throw new TypeError('Cannot convert undefined or null to object'); - } - if (!isObject(obj)) { - obj = {}; - } - for (var i = 1; i < arguments.length; i++) { - var val = arguments[i]; - if (isString(val)) { - val = toObject(val); - } - if (isObject(val)) { - assign(obj, val); - assignSymbols(obj, val); - } - } - return obj; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -function isString(val) { - return (val && typeof val === 'string'); -} - -function toObject(str) { - var obj = {}; - for (var i in str) { - obj[i] = str[i]; - } - return obj; -} - -function isObject(val) { - return (val && typeof val === 'object') || isExtendable(val); -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -function isEnum(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); -} - - -/***/ }), -/* 596 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(597); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 597 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-plain-object - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isObject = __webpack_require__(590); - -function isObjectObject(o) { - return isObject(o) === true - && Object.prototype.toString.call(o) === '[object Object]'; -} - -module.exports = function isPlainObject(o) { - var ctor,prot; - - if (isObjectObject(o) === false) return false; - - // If has modified constructor - ctor = o.constructor; - if (typeof ctor !== 'function') return false; - - // If has modified prototype - prot = ctor.prototype; - if (isObjectObject(prot) === false) return false; - - // If constructor does not have an Object-specific method - if (prot.hasOwnProperty('isPrototypeOf') === false) { - return false; - } - - // Most likely a plain Object - return true; -}; - - -/***/ }), -/* 598 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * assign-symbols - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -module.exports = function(receiver, objects) { - if (receiver === null || typeof receiver === 'undefined') { - throw new TypeError('expected first argument to be an object.'); - } - - if (typeof objects === 'undefined' || typeof Symbol === 'undefined') { - return receiver; - } - - if (typeof Object.getOwnPropertySymbols !== 'function') { - return receiver; - } - - var isEnumerable = Object.prototype.propertyIsEnumerable; - var target = Object(receiver); - var len = arguments.length, i = 0; - - while (++i < len) { - var provider = Object(arguments[i]); - var names = Object.getOwnPropertySymbols(provider); - - for (var j = 0; j < names.length; j++) { - var key = names[j]; - - if (isEnumerable.call(provider, key)) { - target[key] = provider[key]; - } - } - } - return target; -}; - - -/***/ }), -/* 599 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var extend = __webpack_require__(595); -var safe = __webpack_require__(583); - -/** - * The main export is a function that takes a `pattern` string and an `options` object. - * - * ```js - & var not = require('regex-not'); - & console.log(not('foo')); - & //=> /^(?:(?!^(?:foo)$).)*$/ - * ``` - * - * @param {String} `pattern` - * @param {Object} `options` - * @return {RegExp} Converts the given `pattern` to a regex using the specified `options`. - * @api public - */ - -function toRegex(pattern, options) { - return new RegExp(toRegex.create(pattern, options)); -} - -/** - * Create a regex-compatible string from the given `pattern` and `options`. - * - * ```js - & var not = require('regex-not'); - & console.log(not.create('foo')); - & //=> '^(?:(?!^(?:foo)$).)*$' - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {String} - * @api public - */ - -toRegex.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - var opts = extend({}, options); - if (opts.contains === true) { - opts.strictNegate = false; - } - - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var endChar = opts.endChar ? opts.endChar : '+'; - var str = pattern; - - if (opts.strictNegate === false) { - str = '(?:(?!(?:' + pattern + ')).)' + endChar; - } else { - str = '(?:(?!^(?:' + pattern + ')$).)' + endChar; - } - - var res = open + str + close; - if (opts.safe === true && safe(res) === false) { - throw new Error('potentially unsafe regular expression: ' + res); - } - - return res; -}; - -/** - * Expose `toRegex` - */ - -module.exports = toRegex; - - -/***/ }), -/* 600 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * array-unique - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -module.exports = function unique(arr) { - if (!Array.isArray(arr)) { - throw new TypeError('array-unique expects an array.'); - } - - var len = arr.length; - var i = -1; - - while (i++ < len) { - var j = i + 1; - - for (; j < arr.length; ++j) { - if (arr[i] === arr[j]) { - arr.splice(j--, 1); - } - } - } - return arr; -}; - -module.exports.immutable = function uniqueImmutable(arr) { - if (!Array.isArray(arr)) { - throw new TypeError('array-unique expects an array.'); - } - - var arrLen = arr.length; - var newArr = new Array(arrLen); - - for (var i = 0; i < arrLen; i++) { - newArr[i] = arr[i]; - } - - return module.exports(newArr); -}; - - -/***/ }), -/* 601 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(602); - -module.exports = function extend(o/*, objects*/) { - if (!isObject(o)) { o = {}; } - - var len = arguments.length; - for (var i = 1; i < len; i++) { - var obj = arguments[i]; - - if (isObject(obj)) { - assign(o, obj); - } - } - return o; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - - -/***/ }), -/* 602 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -module.exports = function isExtendable(val) { - return typeof val !== 'undefined' && val !== null - && (typeof val === 'object' || typeof val === 'function'); -}; - - -/***/ }), -/* 603 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = __webpack_require__(604); - -module.exports = function(braces, options) { - braces.compiler - - /** - * bos - */ - - .set('bos', function() { - if (this.output) return; - this.ast.queue = isEscaped(this.ast) ? [this.ast.val] : []; - this.ast.count = 1; - }) - - /** - * Square brackets - */ - - .set('bracket', function(node) { - var close = node.close; - var open = !node.escaped ? '[' : '\\['; - var negated = node.negated; - var inner = node.inner; - - inner = inner.replace(/\\(?=[\\\w]|$)/g, '\\\\'); - if (inner === ']-') { - inner = '\\]\\-'; - } - - if (negated && inner.indexOf('.') === -1) { - inner += '.'; - } - if (negated && inner.indexOf('/') === -1) { - inner += '/'; - } - - var val = open + negated + inner + close; - var queue = node.parent.queue; - var last = utils.arrayify(queue.pop()); - - queue.push(utils.join(last, val)); - queue.push.apply(queue, []); - }) - - /** - * Brace - */ - - .set('brace', function(node) { - node.queue = isEscaped(node) ? [node.val] : []; - node.count = 1; - return this.mapVisit(node.nodes); - }) - - /** - * Open - */ - - .set('brace.open', function(node) { - node.parent.open = node.val; - }) - - /** - * Inner - */ - - .set('text', function(node) { - var queue = node.parent.queue; - var escaped = node.escaped; - var segs = [node.val]; - - if (node.optimize === false) { - options = utils.extend({}, options, {optimize: false}); - } - - if (node.multiplier > 1) { - node.parent.count *= node.multiplier; - } - - if (options.quantifiers === true && utils.isQuantifier(node.val)) { - escaped = true; - - } else if (node.val.length > 1) { - if (isType(node.parent, 'brace') && !isEscaped(node)) { - var expanded = utils.expand(node.val, options); - segs = expanded.segs; - - if (expanded.isOptimized) { - node.parent.isOptimized = true; - } - - // if nothing was expanded, we probably have a literal brace - if (!segs.length) { - var val = (expanded.val || node.val); - if (options.unescape !== false) { - // unescape unexpanded brace sequence/set separators - val = val.replace(/\\([,.])/g, '$1'); - // strip quotes - val = val.replace(/["'`]/g, ''); - } - - segs = [val]; - escaped = true; - } - } - - } else if (node.val === ',') { - if (options.expand) { - node.parent.queue.push(['']); - segs = ['']; - } else { - segs = ['|']; - } - } else { - escaped = true; - } - - if (escaped && isType(node.parent, 'brace')) { - if (node.parent.nodes.length <= 4 && node.parent.count === 1) { - node.parent.escaped = true; - } else if (node.parent.length <= 3) { - node.parent.escaped = true; - } - } - - if (!hasQueue(node.parent)) { - node.parent.queue = segs; - return; - } - - var last = utils.arrayify(queue.pop()); - if (node.parent.count > 1 && options.expand) { - last = multiply(last, node.parent.count); - node.parent.count = 1; - } - - queue.push(utils.join(utils.flatten(last), segs.shift())); - queue.push.apply(queue, segs); - }) - - /** - * Close - */ - - .set('brace.close', function(node) { - var queue = node.parent.queue; - var prev = node.parent.parent; - var last = prev.queue.pop(); - var open = node.parent.open; - var close = node.val; - - if (open && close && isOptimized(node, options)) { - open = '('; - close = ')'; - } - - // if a close brace exists, and the previous segment is one character - // don't wrap the result in braces or parens - var ele = utils.last(queue); - if (node.parent.count > 1 && options.expand) { - ele = multiply(queue.pop(), node.parent.count); - node.parent.count = 1; - queue.push(ele); - } - - if (close && typeof ele === 'string' && ele.length === 1) { - open = ''; - close = ''; - } - - if ((isLiteralBrace(node, options) || noInner(node)) && !node.parent.hasEmpty) { - queue.push(utils.join(open, queue.pop() || '')); - queue = utils.flatten(utils.join(queue, close)); - } - - if (typeof last === 'undefined') { - prev.queue = [queue]; - } else { - prev.queue.push(utils.flatten(utils.join(last, queue))); - } - }) - - /** - * eos - */ - - .set('eos', function(node) { - if (this.input) return; - - if (options.optimize !== false) { - this.output = utils.last(utils.flatten(this.ast.queue)); - } else if (Array.isArray(utils.last(this.ast.queue))) { - this.output = utils.flatten(this.ast.queue.pop()); - } else { - this.output = utils.flatten(this.ast.queue); - } - - if (node.parent.count > 1 && options.expand) { - this.output = multiply(this.output, node.parent.count); - } - - this.output = utils.arrayify(this.output); - this.ast.queue = []; - }); - -}; - -/** - * Multiply the segments in the current brace level - */ - -function multiply(queue, n, options) { - return utils.flatten(utils.repeat(utils.arrayify(queue), n)); -} - -/** - * Return true if `node` is escaped - */ - -function isEscaped(node) { - return node.escaped === true; -} - -/** - * Returns true if regex parens should be used for sets. If the parent `type` - * is not `brace`, then we're on a root node, which means we should never - * expand segments and open/close braces should be `{}` (since this indicates - * a brace is missing from the set) - */ - -function isOptimized(node, options) { - if (node.parent.isOptimized) return true; - return isType(node.parent, 'brace') - && !isEscaped(node.parent) - && options.expand !== true; -} - -/** - * Returns true if the value in `node` should be wrapped in a literal brace. - * @return {Boolean} - */ - -function isLiteralBrace(node, options) { - return isEscaped(node.parent) || options.optimize !== false; -} - -/** - * Returns true if the given `node` does not have an inner value. - * @return {Boolean} - */ - -function noInner(node, type) { - if (node.parent.queue.length === 1) { - return true; - } - var nodes = node.parent.nodes; - return nodes.length === 3 - && isType(nodes[0], 'brace.open') - && !isType(nodes[1], 'text') - && isType(nodes[2], 'brace.close'); -} - -/** - * Returns true if the given `node` is the given `type` - * @return {Boolean} - */ - -function isType(node, type) { - return typeof node !== 'undefined' && node.type === type; -} - -/** - * Returns true if the given `node` has a non-empty queue. - * @return {Boolean} - */ - -function hasQueue(node) { - return Array.isArray(node.queue) && node.queue.length; -} - - -/***/ }), -/* 604 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var splitString = __webpack_require__(605); -var utils = module.exports; - -/** - * Module dependencies - */ - -utils.extend = __webpack_require__(601); -utils.flatten = __webpack_require__(606); -utils.isObject = __webpack_require__(590); -utils.fillRange = __webpack_require__(607); -utils.repeat = __webpack_require__(612); -utils.unique = __webpack_require__(600); - -utils.define = function(obj, key, val) { - Object.defineProperty(obj, key, { - writable: true, - configurable: true, - enumerable: false, - value: val - }); -}; - -/** - * Returns true if the given string contains only empty brace sets. - */ - -utils.isEmptySets = function(str) { - return /^(?:\{,\})+$/.test(str); -}; - -/** - * Returns true if the given string contains only empty brace sets. - */ - -utils.isQuotedString = function(str) { - var open = str.charAt(0); - if (open === '\'' || open === '"' || open === '`') { - return str.slice(-1) === open; - } - return false; -}; - -/** - * Create the key to use for memoization. The unique key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -utils.createKey = function(pattern, options) { - var id = pattern; - if (typeof options === 'undefined') { - return id; - } - var keys = Object.keys(options); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - id += ';' + key + '=' + String(options[key]); - } - return id; -}; - -/** - * Normalize options - */ - -utils.createOptions = function(options) { - var opts = utils.extend.apply(null, arguments); - if (typeof opts.expand === 'boolean') { - opts.optimize = !opts.expand; - } - if (typeof opts.optimize === 'boolean') { - opts.expand = !opts.optimize; - } - if (opts.optimize === true) { - opts.makeRe = true; - } - return opts; -}; - -/** - * Join patterns in `a` to patterns in `b` - */ - -utils.join = function(a, b, options) { - options = options || {}; - a = utils.arrayify(a); - b = utils.arrayify(b); - - if (!a.length) return b; - if (!b.length) return a; - - var len = a.length; - var idx = -1; - var arr = []; - - while (++idx < len) { - var val = a[idx]; - if (Array.isArray(val)) { - for (var i = 0; i < val.length; i++) { - val[i] = utils.join(val[i], b, options); - } - arr.push(val); - continue; - } - - for (var j = 0; j < b.length; j++) { - var bval = b[j]; - - if (Array.isArray(bval)) { - arr.push(utils.join(val, bval, options)); - } else { - arr.push(val + bval); - } - } - } - return arr; -}; - -/** - * Split the given string on `,` if not escaped. - */ - -utils.split = function(str, options) { - var opts = utils.extend({sep: ','}, options); - if (typeof opts.keepQuotes !== 'boolean') { - opts.keepQuotes = true; - } - if (opts.unescape === false) { - opts.keepEscaping = true; - } - return splitString(str, opts, utils.escapeBrackets(opts)); -}; - -/** - * Expand ranges or sets in the given `pattern`. - * - * @param {String} `str` - * @param {Object} `options` - * @return {Object} - */ - -utils.expand = function(str, options) { - var opts = utils.extend({rangeLimit: 10000}, options); - var segs = utils.split(str, opts); - var tok = { segs: segs }; - - if (utils.isQuotedString(str)) { - return tok; - } - - if (opts.rangeLimit === true) { - opts.rangeLimit = 10000; - } - - if (segs.length > 1) { - if (opts.optimize === false) { - tok.val = segs[0]; - return tok; - } - - tok.segs = utils.stringifyArray(tok.segs); - } else if (segs.length === 1) { - var arr = str.split('..'); - - if (arr.length === 1) { - tok.val = tok.segs[tok.segs.length - 1] || tok.val || str; - tok.segs = []; - return tok; - } - - if (arr.length === 2 && arr[0] === arr[1]) { - tok.escaped = true; - tok.val = arr[0]; - tok.segs = []; - return tok; - } - - if (arr.length > 1) { - if (opts.optimize !== false) { - opts.optimize = true; - delete opts.expand; - } - - if (opts.optimize !== true) { - var min = Math.min(arr[0], arr[1]); - var max = Math.max(arr[0], arr[1]); - var step = arr[2] || 1; - - if (opts.rangeLimit !== false && ((max - min) / step >= opts.rangeLimit)) { - throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); - } - } - - arr.push(opts); - tok.segs = utils.fillRange.apply(null, arr); - - if (!tok.segs.length) { - tok.escaped = true; - tok.val = str; - return tok; - } - - if (opts.optimize === true) { - tok.segs = utils.stringifyArray(tok.segs); - } - - if (tok.segs === '') { - tok.val = str; - } else { - tok.val = tok.segs[0]; - } - return tok; - } - } else { - tok.val = str; - } - return tok; -}; - -/** - * Ensure commas inside brackets and parens are not split. - * @param {Object} `tok` Token from the `split-string` module - * @return {undefined} - */ - -utils.escapeBrackets = function(options) { - return function(tok) { - if (tok.escaped && tok.val === 'b') { - tok.val = '\\b'; - return; - } - - if (tok.val !== '(' && tok.val !== '[') return; - var opts = utils.extend({}, options); - var brackets = []; - var parens = []; - var stack = []; - var val = tok.val; - var str = tok.str; - var i = tok.idx - 1; - - while (++i < str.length) { - var ch = str[i]; - - if (ch === '\\') { - val += (opts.keepEscaping === false ? '' : ch) + str[++i]; - continue; - } - - if (ch === '(') { - parens.push(ch); - stack.push(ch); - } - - if (ch === '[') { - brackets.push(ch); - stack.push(ch); - } - - if (ch === ')') { - parens.pop(); - stack.pop(); - if (!stack.length) { - val += ch; - break; - } - } - - if (ch === ']') { - brackets.pop(); - stack.pop(); - if (!stack.length) { - val += ch; - break; - } - } - val += ch; - } - - tok.split = false; - tok.val = val.slice(1); - tok.idx = i; - }; -}; - -/** - * Returns true if the given string looks like a regex quantifier - * @return {Boolean} - */ - -utils.isQuantifier = function(str) { - return /^(?:[0-9]?,[0-9]|[0-9],)$/.test(str); -}; - -/** - * Cast `val` to an array. - * @param {*} `val` - */ - -utils.stringifyArray = function(arr) { - return [utils.arrayify(arr).join('|')]; -}; - -/** - * Cast `val` to an array. - * @param {*} `val` - */ - -utils.arrayify = function(arr) { - if (typeof arr === 'undefined') { - return []; - } - if (typeof arr === 'string') { - return [arr]; - } - return arr; -}; - -/** - * Returns true if the given `str` is a non-empty string - * @return {Boolean} - */ - -utils.isString = function(str) { - return str != null && typeof str === 'string'; -}; - -/** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} - */ - -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - -utils.escapeRegex = function(str) { - return str.replace(/\\?([!^*?()[\]{}+?/])/g, '\\$1'); -}; - - -/***/ }), -/* 605 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * split-string - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var extend = __webpack_require__(595); - -module.exports = function(str, options, fn) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - if (typeof options === 'function') { - fn = options; - options = null; - } - - // allow separator to be defined as a string - if (typeof options === 'string') { - options = { sep: options }; - } - - var opts = extend({sep: '.'}, options); - var quotes = opts.quotes || ['"', "'", '`']; - var brackets; - - if (opts.brackets === true) { - brackets = { - '<': '>', - '(': ')', - '[': ']', - '{': '}' - }; - } else if (opts.brackets) { - brackets = opts.brackets; - } - - var tokens = []; - var stack = []; - var arr = ['']; - var sep = opts.sep; - var len = str.length; - var idx = -1; - var closeIdx; - - function expected() { - if (brackets && stack.length) { - return brackets[stack[stack.length - 1]]; - } - } - - while (++idx < len) { - var ch = str[idx]; - var next = str[idx + 1]; - var tok = { val: ch, idx: idx, arr: arr, str: str }; - tokens.push(tok); - - if (ch === '\\') { - tok.val = keepEscaping(opts, str, idx) === true ? (ch + next) : next; - tok.escaped = true; - if (typeof fn === 'function') { - fn(tok); - } - arr[arr.length - 1] += tok.val; - idx++; - continue; - } - - if (brackets && brackets[ch]) { - stack.push(ch); - var e = expected(); - var i = idx + 1; - - if (str.indexOf(e, i + 1) !== -1) { - while (stack.length && i < len) { - var s = str[++i]; - if (s === '\\') { - s++; - continue; - } - - if (quotes.indexOf(s) !== -1) { - i = getClosingQuote(str, s, i + 1); - continue; - } - - e = expected(); - if (stack.length && str.indexOf(e, i + 1) === -1) { - break; - } - - if (brackets[s]) { - stack.push(s); - continue; - } - - if (e === s) { - stack.pop(); - } - } - } - - closeIdx = i; - if (closeIdx === -1) { - arr[arr.length - 1] += ch; - continue; - } - - ch = str.slice(idx, closeIdx + 1); - tok.val = ch; - tok.idx = idx = closeIdx; - } - - if (quotes.indexOf(ch) !== -1) { - closeIdx = getClosingQuote(str, ch, idx + 1); - if (closeIdx === -1) { - arr[arr.length - 1] += ch; - continue; - } - - if (keepQuotes(ch, opts) === true) { - ch = str.slice(idx, closeIdx + 1); - } else { - ch = str.slice(idx + 1, closeIdx); - } - - tok.val = ch; - tok.idx = idx = closeIdx; - } - - if (typeof fn === 'function') { - fn(tok, tokens); - ch = tok.val; - idx = tok.idx; - } - - if (tok.val === sep && tok.split !== false) { - arr.push(''); - continue; - } - - arr[arr.length - 1] += tok.val; - } - - return arr; -}; - -function getClosingQuote(str, ch, i, brackets) { - var idx = str.indexOf(ch, i); - if (str.charAt(idx - 1) === '\\') { - return getClosingQuote(str, ch, idx + 1); - } - return idx; -} - -function keepQuotes(ch, opts) { - if (opts.keepDoubleQuotes === true && ch === '"') return true; - if (opts.keepSingleQuotes === true && ch === "'") return true; - return opts.keepQuotes; -} - -function keepEscaping(opts, str, idx) { - if (typeof opts.keepEscaping === 'function') { - return opts.keepEscaping(str, idx); - } - return opts.keepEscaping === true || str[idx + 1] === '\\'; -} - - -/***/ }), -/* 606 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * arr-flatten - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function (arr) { - return flat(arr, []); -}; - -function flat(arr, res) { - var i = 0, cur; - var len = arr.length; - for (; i < len; i++) { - cur = arr[i]; - Array.isArray(cur) ? flat(cur, res) : res.push(cur); - } - return res; -} - - -/***/ }), -/* 607 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * fill-range - * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var util = __webpack_require__(112); -var isNumber = __webpack_require__(608); -var extend = __webpack_require__(609); -var repeat = __webpack_require__(610); -var toRegex = __webpack_require__(611); - -/** - * Return a range of numbers or letters. - * - * @param {String} `start` Start of the range - * @param {String} `stop` End of the range - * @param {String} `step` Increment or decrement to use. - * @param {Function} `fn` Custom function to modify each element in the range. - * @return {Array} - */ - -function fillRange(start, stop, step, options) { - if (typeof start === 'undefined') { - return []; - } - - if (typeof stop === 'undefined' || start === stop) { - // special case, for handling negative zero - var isString = typeof start === 'string'; - if (isNumber(start) && !toNumber(start)) { - return [isString ? '0' : 0]; - } - return [start]; - } - - if (typeof step !== 'number' && typeof step !== 'string') { - options = step; - step = undefined; - } - - if (typeof options === 'function') { - options = { transform: options }; - } - - var opts = extend({step: step}, options); - if (opts.step && !isValidNumber(opts.step)) { - if (opts.strictRanges === true) { - throw new TypeError('expected options.step to be a number'); - } - return []; - } - - opts.isNumber = isValidNumber(start) && isValidNumber(stop); - if (!opts.isNumber && !isValid(start, stop)) { - if (opts.strictRanges === true) { - throw new RangeError('invalid range arguments: ' + util.inspect([start, stop])); - } - return []; - } - - opts.isPadded = isPadded(start) || isPadded(stop); - opts.toString = opts.stringify - || typeof opts.step === 'string' - || typeof start === 'string' - || typeof stop === 'string' - || !opts.isNumber; - - if (opts.isPadded) { - opts.maxLength = Math.max(String(start).length, String(stop).length); - } - - // support legacy minimatch/fill-range options - if (typeof opts.optimize === 'boolean') opts.toRegex = opts.optimize; - if (typeof opts.makeRe === 'boolean') opts.toRegex = opts.makeRe; - return expand(start, stop, opts); -} - -function expand(start, stop, options) { - var a = options.isNumber ? toNumber(start) : start.charCodeAt(0); - var b = options.isNumber ? toNumber(stop) : stop.charCodeAt(0); - - var step = Math.abs(toNumber(options.step)) || 1; - if (options.toRegex && step === 1) { - return toRange(a, b, start, stop, options); - } - - var zero = {greater: [], lesser: []}; - var asc = a < b; - var arr = new Array(Math.round((asc ? b - a : a - b) / step)); - var idx = 0; - - while (asc ? a <= b : a >= b) { - var val = options.isNumber ? a : String.fromCharCode(a); - if (options.toRegex && (val >= 0 || !options.isNumber)) { - zero.greater.push(val); - } else { - zero.lesser.push(Math.abs(val)); - } - - if (options.isPadded) { - val = zeros(val, options); - } - - if (options.toString) { - val = String(val); - } - - if (typeof options.transform === 'function') { - arr[idx++] = options.transform(val, a, b, step, idx, arr, options); - } else { - arr[idx++] = val; - } - - if (asc) { - a += step; - } else { - a -= step; - } - } - - if (options.toRegex === true) { - return toSequence(arr, zero, options); - } - return arr; -} - -function toRange(a, b, start, stop, options) { - if (options.isPadded) { - return toRegex(start, stop, options); - } - - if (options.isNumber) { - return toRegex(Math.min(a, b), Math.max(a, b), options); - } - - var start = String.fromCharCode(Math.min(a, b)); - var stop = String.fromCharCode(Math.max(a, b)); - return '[' + start + '-' + stop + ']'; -} - -function toSequence(arr, zeros, options) { - var greater = '', lesser = ''; - if (zeros.greater.length) { - greater = zeros.greater.join('|'); - } - if (zeros.lesser.length) { - lesser = '-(' + zeros.lesser.join('|') + ')'; - } - var res = greater && lesser - ? greater + '|' + lesser - : greater || lesser; - - if (options.capture) { - return '(' + res + ')'; - } - return res; -} - -function zeros(val, options) { - if (options.isPadded) { - var str = String(val); - var len = str.length; - var dash = ''; - if (str.charAt(0) === '-') { - dash = '-'; - str = str.slice(1); - } - var diff = options.maxLength - len; - var pad = repeat('0', diff); - val = (dash + pad + str); - } - if (options.stringify) { - return String(val); - } - return val; -} - -function toNumber(val) { - return Number(val) || 0; -} - -function isPadded(str) { - return /^-?0\d/.test(str); -} - -function isValid(min, max) { - return (isValidNumber(min) || isValidLetter(min)) - && (isValidNumber(max) || isValidLetter(max)); -} - -function isValidLetter(ch) { - return typeof ch === 'string' && ch.length === 1 && /^\w+$/.test(ch); -} - -function isValidNumber(n) { - return isNumber(n) && !/\./.test(n); -} - -/** - * Expose `fillRange` - * @type {Function} - */ - -module.exports = fillRange; - - -/***/ }), -/* 608 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-number - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); - -module.exports = function isNumber(num) { - var type = typeOf(num); - - if (type === 'string') { - if (!num.trim()) return false; - } else if (type !== 'number') { - return false; - } - - return (num - num + 1) >= 0; -}; - - -/***/ }), -/* 609 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(602); - -module.exports = function extend(o/*, objects*/) { - if (!isObject(o)) { o = {}; } - - var len = arguments.length; - for (var i = 1; i < len; i++) { - var obj = arguments[i]; - - if (isObject(obj)) { - assign(o, obj); - } - } - return o; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - - -/***/ }), -/* 610 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * repeat-string - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -/** - * Results cache - */ - -var res = ''; -var cache; - -/** - * Expose `repeat` - */ - -module.exports = repeat; - -/** - * Repeat the given `string` the specified `number` - * of times. - * - * **Example:** - * - * ```js - * var repeat = require('repeat-string'); - * repeat('A', 5); - * //=> AAAAA - * ``` - * - * @param {String} `string` The string to repeat - * @param {Number} `number` The number of times to repeat the string - * @return {String} Repeated string - * @api public - */ - -function repeat(str, num) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - // cover common, quick use cases - if (num === 1) return str; - if (num === 2) return str + str; - - var max = str.length * num; - if (cache !== str || typeof cache === 'undefined') { - cache = str; - res = ''; - } else if (res.length >= max) { - return res.substr(0, max); - } - - while (max > res.length && num > 1) { - if (num & 1) { - res += str; - } - - num >>= 1; - str += str; - } - - res += str; - res = res.substr(0, max); - return res; -} - - -/***/ }), -/* 611 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * to-regex-range - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var repeat = __webpack_require__(610); -var isNumber = __webpack_require__(608); -var cache = {}; - -function toRegexRange(min, max, options) { - if (isNumber(min) === false) { - throw new RangeError('toRegexRange: first argument is invalid.'); - } - - if (typeof max === 'undefined' || min === max) { - return String(min); - } - - if (isNumber(max) === false) { - throw new RangeError('toRegexRange: second argument is invalid.'); - } - - options = options || {}; - var relax = String(options.relaxZeros); - var shorthand = String(options.shorthand); - var capture = String(options.capture); - var key = min + ':' + max + '=' + relax + shorthand + capture; - if (cache.hasOwnProperty(key)) { - return cache[key].result; - } - - var a = Math.min(min, max); - var b = Math.max(min, max); - - if (Math.abs(a - b) === 1) { - var result = min + '|' + max; - if (options.capture) { - return '(' + result + ')'; - } - return result; - } - - var isPadded = padding(min) || padding(max); - var positives = []; - var negatives = []; - - var tok = {min: min, max: max, a: a, b: b}; - if (isPadded) { - tok.isPadded = isPadded; - tok.maxLen = String(tok.max).length; - } - - if (a < 0) { - var newMin = b < 0 ? Math.abs(b) : 1; - var newMax = Math.abs(a); - negatives = splitToPatterns(newMin, newMax, tok, options); - a = tok.a = 0; - } - - if (b >= 0) { - positives = splitToPatterns(a, b, tok, options); - } - - tok.negatives = negatives; - tok.positives = positives; - tok.result = siftPatterns(negatives, positives, options); - - if (options.capture && (positives.length + negatives.length) > 1) { - tok.result = '(' + tok.result + ')'; - } - - cache[key] = tok; - return tok.result; -} - -function siftPatterns(neg, pos, options) { - var onlyNegative = filterPatterns(neg, pos, '-', false, options) || []; - var onlyPositive = filterPatterns(pos, neg, '', false, options) || []; - var intersected = filterPatterns(neg, pos, '-?', true, options) || []; - var subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); - return subpatterns.join('|'); -} - -function splitToRanges(min, max) { - min = Number(min); - max = Number(max); - - var nines = 1; - var stops = [max]; - var stop = +countNines(min, nines); - - while (min <= stop && stop <= max) { - stops = push(stops, stop); - nines += 1; - stop = +countNines(min, nines); - } - - var zeros = 1; - stop = countZeros(max + 1, zeros) - 1; - - while (min < stop && stop <= max) { - stops = push(stops, stop); - zeros += 1; - stop = countZeros(max + 1, zeros) - 1; - } - - stops.sort(compare); - return stops; -} - -/** - * Convert a range to a regex pattern - * @param {Number} `start` - * @param {Number} `stop` - * @return {String} - */ - -function rangeToPattern(start, stop, options) { - if (start === stop) { - return {pattern: String(start), digits: []}; - } - - var zipped = zip(String(start), String(stop)); - var len = zipped.length, i = -1; - - var pattern = ''; - var digits = 0; - - while (++i < len) { - var numbers = zipped[i]; - var startDigit = numbers[0]; - var stopDigit = numbers[1]; - - if (startDigit === stopDigit) { - pattern += startDigit; - - } else if (startDigit !== '0' || stopDigit !== '9') { - pattern += toCharacterClass(startDigit, stopDigit); - - } else { - digits += 1; - } - } - - if (digits) { - pattern += options.shorthand ? '\\d' : '[0-9]'; - } - - return { pattern: pattern, digits: [digits] }; -} - -function splitToPatterns(min, max, tok, options) { - var ranges = splitToRanges(min, max); - var len = ranges.length; - var idx = -1; - - var tokens = []; - var start = min; - var prev; - - while (++idx < len) { - var range = ranges[idx]; - var obj = rangeToPattern(start, range, options); - var zeros = ''; - - if (!tok.isPadded && prev && prev.pattern === obj.pattern) { - if (prev.digits.length > 1) { - prev.digits.pop(); - } - prev.digits.push(obj.digits[0]); - prev.string = prev.pattern + toQuantifier(prev.digits); - start = range + 1; - continue; - } - - if (tok.isPadded) { - zeros = padZeros(range, tok); - } - - obj.string = zeros + obj.pattern + toQuantifier(obj.digits); - tokens.push(obj); - start = range + 1; - prev = obj; - } - - return tokens; -} - -function filterPatterns(arr, comparison, prefix, intersection, options) { - var res = []; - - for (var i = 0; i < arr.length; i++) { - var tok = arr[i]; - var ele = tok.string; - - if (options.relaxZeros !== false) { - if (prefix === '-' && ele.charAt(0) === '0') { - if (ele.charAt(1) === '{') { - ele = '0*' + ele.replace(/^0\{\d+\}/, ''); - } else { - ele = '0*' + ele.slice(1); - } - } - } - - if (!intersection && !contains(comparison, 'string', ele)) { - res.push(prefix + ele); - } - - if (intersection && contains(comparison, 'string', ele)) { - res.push(prefix + ele); - } - } - return res; -} - -/** - * Zip strings (`for in` can be used on string characters) - */ - -function zip(a, b) { - var arr = []; - for (var ch in a) arr.push([a[ch], b[ch]]); - return arr; -} - -function compare(a, b) { - return a > b ? 1 : b > a ? -1 : 0; -} - -function push(arr, ele) { - if (arr.indexOf(ele) === -1) arr.push(ele); - return arr; -} - -function contains(arr, key, val) { - for (var i = 0; i < arr.length; i++) { - if (arr[i][key] === val) { - return true; - } - } - return false; -} - -function countNines(min, len) { - return String(min).slice(0, -len) + repeat('9', len); -} - -function countZeros(integer, zeros) { - return integer - (integer % Math.pow(10, zeros)); -} - -function toQuantifier(digits) { - var start = digits[0]; - var stop = digits[1] ? (',' + digits[1]) : ''; - if (!stop && (!start || start === 1)) { - return ''; - } - return '{' + start + stop + '}'; -} - -function toCharacterClass(a, b) { - return '[' + a + ((b - a === 1) ? '' : '-') + b + ']'; -} - -function padding(str) { - return /^-?(0+)\d/.exec(str); -} - -function padZeros(val, tok) { - if (tok.isPadded) { - var diff = Math.abs(tok.maxLen - String(val).length); - switch (diff) { - case 0: - return ''; - case 1: - return '0'; - default: { - return '0{' + diff + '}'; - } - } - } - return val; -} - -/** - * Expose `toRegexRange` - */ - -module.exports = toRegexRange; - - -/***/ }), -/* 612 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * repeat-element - * - * Copyright (c) 2015-present, Jon Schlinkert. - * Licensed under the MIT license. - */ - - - -module.exports = function repeat(ele, num) { - if (Array.prototype.fill) { - return new Array(num).fill(ele); - } - - var arr = new Array(num); - - for (var i = 0; i < num; i++) { - arr[i] = ele; - } - - return arr; -}; - - -/***/ }), -/* 613 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Node = __webpack_require__(614); -var utils = __webpack_require__(604); - -/** - * Braces parsers - */ - -module.exports = function(braces, options) { - braces.parser - .set('bos', function() { - if (!this.parsed) { - this.ast = this.nodes[0] = new Node(this.ast); - } - }) - - /** - * Character parsers - */ - - .set('escape', function() { - var pos = this.position(); - var m = this.match(/^(?:\\(.)|\$\{)/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - var node = pos(new Node({ - type: 'text', - multiplier: 1, - val: m[0] - })); - - if (node.val === '\\\\') { - return node; - } - - if (node.val === '${') { - var str = this.input; - var idx = -1; - var ch; - - while ((ch = str[++idx])) { - this.consume(1); - node.val += ch; - if (ch === '\\') { - node.val += str[++idx]; - continue; - } - if (ch === '}') { - break; - } - } - } - - if (this.options.unescape !== false) { - node.val = node.val.replace(/\\([{}])/g, '$1'); - } - - if (last.val === '"' && this.input.charAt(0) === '"') { - last.val = node.val; - this.consume(1); - return; - } - - return concatNodes.call(this, pos, node, prev, options); - }) - - /** - * Brackets: "[...]" (basic, this is overridden by - * other parsers in more advanced implementations) - */ - - .set('bracket', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^(?:\[([!^]?)([^\]]{2,}|\]-)(\]|[^*+?]+)|\[)/); - if (!m) return; - - var prev = this.prev(); - var val = m[0]; - var negated = m[1] ? '^' : ''; - var inner = m[2] || ''; - var close = m[3] || ''; - - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } - - var esc = this.input.slice(0, 2); - if (inner === '' && esc === '\\]') { - inner += esc; - this.consume(2); - - var str = this.input; - var idx = -1; - var ch; - - while ((ch = str[++idx])) { - this.consume(1); - if (ch === ']') { - close = ch; - break; - } - inner += ch; - } - } - - return pos(new Node({ - type: 'bracket', - val: val, - escaped: close !== ']', - negated: negated, - inner: inner, - close: close - })); - }) - - /** - * Empty braces (we capture these early to - * speed up processing in the compiler) - */ - - .set('multiplier', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^\{((?:,|\{,+\})+)\}/); - if (!m) return; - - this.multiplier = true; - var prev = this.prev(); - var val = m[0]; - - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } - - var node = pos(new Node({ - type: 'text', - multiplier: 1, - match: m, - val: val - })); - - return concatNodes.call(this, pos, node, prev, options); - }) - - /** - * Open - */ - - .set('brace.open', function() { - var pos = this.position(); - var m = this.match(/^\{(?!(?:[^\\}]?|,+)\})/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - // if the last parsed character was an extglob character - // we need to _not optimize_ the brace pattern because - // it might be mistaken for an extglob by a downstream parser - if (last && last.val && isExtglobChar(last.val.slice(-1))) { - last.optimize = false; - } - - var open = pos(new Node({ - type: 'brace.open', - val: m[0] - })); - - var node = pos(new Node({ - type: 'brace', - nodes: [] - })); - - node.push(open); - prev.push(node); - this.push('brace', node); - }) - - /** - * Close - */ - - .set('brace.close', function() { - var pos = this.position(); - var m = this.match(/^\}/); - if (!m || !m[0]) return; - - var brace = this.pop('brace'); - var node = pos(new Node({ - type: 'brace.close', - val: m[0] - })); - - if (!this.isType(brace, 'brace')) { - if (this.options.strict) { - throw new Error('missing opening "{"'); - } - node.type = 'text'; - node.multiplier = 0; - node.escaped = true; - return node; - } - - var prev = this.prev(); - var last = utils.last(prev.nodes); - if (last.text) { - var lastNode = utils.last(last.nodes); - if (lastNode.val === ')' && /[!@*?+]\(/.test(last.text)) { - var open = last.nodes[0]; - var text = last.nodes[1]; - if (open.type === 'brace.open' && text && text.type === 'text') { - text.optimize = false; - } - } - } - - if (brace.nodes.length > 2) { - var first = brace.nodes[1]; - if (first.type === 'text' && first.val === ',') { - brace.nodes.splice(1, 1); - brace.nodes.push(first); - } - } - - brace.push(node); - }) - - /** - * Capture boundary characters - */ - - .set('boundary', function() { - var pos = this.position(); - var m = this.match(/^[$^](?!\{)/); - if (!m) return; - return pos(new Node({ - type: 'text', - val: m[0] - })); - }) - - /** - * One or zero, non-comma characters wrapped in braces - */ - - .set('nobrace', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^\{[^,]?\}/); - if (!m) return; - - var prev = this.prev(); - var val = m[0]; - - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } - - return pos(new Node({ - type: 'text', - multiplier: 0, - val: val - })); - }) - - /** - * Text - */ - - .set('text', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^((?!\\)[^${}[\]])+/); - if (!m) return; - - var prev = this.prev(); - var val = m[0]; - - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } - - var node = pos(new Node({ - type: 'text', - multiplier: 1, - val: val - })); - - return concatNodes.call(this, pos, node, prev, options); - }); -}; - -/** - * Returns true if the character is an extglob character. - */ - -function isExtglobChar(ch) { - return ch === '!' || ch === '@' || ch === '*' || ch === '?' || ch === '+'; -} - -/** - * Combine text nodes, and calculate empty sets (`{,,}`) - * @param {Function} `pos` Function to calculate node position - * @param {Object} `node` AST node - * @return {Object} - */ - -function concatNodes(pos, node, parent, options) { - node.orig = node.val; - var prev = this.prev(); - var last = utils.last(prev.nodes); - var isEscaped = false; - - if (node.val.length > 1) { - var a = node.val.charAt(0); - var b = node.val.slice(-1); - - isEscaped = (a === '"' && b === '"') - || (a === "'" && b === "'") - || (a === '`' && b === '`'); - } - - if (isEscaped && options.unescape !== false) { - node.val = node.val.slice(1, node.val.length - 1); - node.escaped = true; - } - - if (node.match) { - var match = node.match[1]; - if (!match || match.indexOf('}') === -1) { - match = node.match[0]; - } - - // replace each set with a single "," - var val = match.replace(/\{/g, ',').replace(/\}/g, ''); - node.multiplier *= val.length; - node.val = ''; - } - - var simpleText = last.type === 'text' - && last.multiplier === 1 - && node.multiplier === 1 - && node.val; - - if (simpleText) { - last.val += node.val; - return; - } - - prev.push(node); -} - - -/***/ }), -/* 614 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(590); -var define = __webpack_require__(615); -var utils = __webpack_require__(616); -var ownNames; - -/** - * Create a new AST `Node` with the given `val` and `type`. - * - * ```js - * var node = new Node('*', 'Star'); - * var node = new Node({type: 'star', val: '*'}); - * ``` - * @name Node - * @param {String|Object} `val` Pass a matched substring, or an object to merge onto the node. - * @param {String} `type` The node type to use when `val` is a string. - * @return {Object} node instance - * @api public - */ - -function Node(val, type, parent) { - if (typeof type !== 'string') { - parent = type; - type = null; - } - - define(this, 'parent', parent); - define(this, 'isNode', true); - define(this, 'expect', null); - - if (typeof type !== 'string' && isObject(val)) { - lazyKeys(); - var keys = Object.keys(val); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (ownNames.indexOf(key) === -1) { - this[key] = val[key]; - } - } - } else { - this.type = type; - this.val = val; - } -} - -/** - * Returns true if the given value is a node. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(Node.isNode(node)); //=> true - * console.log(Node.isNode({})); //=> false - * ``` - * @param {Object} `node` - * @returns {Boolean} - * @api public - */ - -Node.isNode = function(node) { - return utils.isNode(node); -}; - -/** - * Define a non-enumberable property on the node instance. - * Useful for adding properties that shouldn't be extended - * or visible during debugging. - * - * ```js - * var node = new Node(); - * node.define('foo', 'something non-enumerable'); - * ``` - * @param {String} `name` - * @param {any} `val` - * @return {Object} returns the node instance - * @api public - */ - -Node.prototype.define = function(name, val) { - define(this, name, val); - return this; -}; - -/** - * Returns true if `node.val` is an empty string, or `node.nodes` does - * not contain any non-empty text nodes. - * - * ```js - * var node = new Node({type: 'text'}); - * node.isEmpty(); //=> true - * node.val = 'foo'; - * node.isEmpty(); //=> false - * ``` - * @param {Function} `fn` (optional) Filter function that is called on `node` and/or child nodes. `isEmpty` will return false immediately when the filter function returns false on any nodes. - * @return {Boolean} - * @api public - */ - -Node.prototype.isEmpty = function(fn) { - return utils.isEmpty(this, fn); -}; - -/** - * Given node `foo` and node `bar`, push node `bar` onto `foo.nodes`, and - * set `foo` as `bar.parent`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.push(bar); - * ``` - * @param {Object} `node` - * @return {Number} Returns the length of `node.nodes` - * @api public - */ - -Node.prototype.push = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - define(node, 'parent', this); - - this.nodes = this.nodes || []; - return this.nodes.push(node); -}; - -/** - * Given node `foo` and node `bar`, unshift node `bar` onto `foo.nodes`, and - * set `foo` as `bar.parent`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.unshift(bar); - * ``` - * @param {Object} `node` - * @return {Number} Returns the length of `node.nodes` - * @api public - */ - -Node.prototype.unshift = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - define(node, 'parent', this); - - this.nodes = this.nodes || []; - return this.nodes.unshift(node); -}; - -/** - * Pop a node from `node.nodes`. - * - * ```js - * var node = new Node({type: 'foo'}); - * node.push(new Node({type: 'a'})); - * node.push(new Node({type: 'b'})); - * node.push(new Node({type: 'c'})); - * node.push(new Node({type: 'd'})); - * console.log(node.nodes.length); - * //=> 4 - * node.pop(); - * console.log(node.nodes.length); - * //=> 3 - * ``` - * @return {Number} Returns the popped `node` - * @api public - */ - -Node.prototype.pop = function() { - return this.nodes && this.nodes.pop(); -}; - -/** - * Shift a node from `node.nodes`. - * - * ```js - * var node = new Node({type: 'foo'}); - * node.push(new Node({type: 'a'})); - * node.push(new Node({type: 'b'})); - * node.push(new Node({type: 'c'})); - * node.push(new Node({type: 'd'})); - * console.log(node.nodes.length); - * //=> 4 - * node.shift(); - * console.log(node.nodes.length); - * //=> 3 - * ``` - * @return {Object} Returns the shifted `node` - * @api public - */ - -Node.prototype.shift = function() { - return this.nodes && this.nodes.shift(); -}; - -/** - * Remove `node` from `node.nodes`. - * - * ```js - * node.remove(childNode); - * ``` - * @param {Object} `node` - * @return {Object} Returns the removed node. - * @api public - */ - -Node.prototype.remove = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - this.nodes = this.nodes || []; - var idx = node.index; - if (idx !== -1) { - node.index = -1; - return this.nodes.splice(idx, 1); - } - return null; -}; - -/** - * Get the first child node from `node.nodes` that matches the given `type`. - * If `type` is a number, the child node at that index is returned. - * - * ```js - * var child = node.find(1); //<= index of the node to get - * var child = node.find('foo'); //<= node.type of a child node - * var child = node.find(/^(foo|bar)$/); //<= regex to match node.type - * var child = node.find(['foo', 'bar']); //<= array of node.type(s) - * ``` - * @param {String} `type` - * @return {Object} Returns a child node or undefined. - * @api public - */ - -Node.prototype.find = function(type) { - return utils.findNode(this.nodes, type); -}; - -/** - * Return true if the node is the given `type`. - * - * ```js - * var node = new Node({type: 'bar'}); - * cosole.log(node.isType('foo')); // false - * cosole.log(node.isType(/^(foo|bar)$/)); // true - * cosole.log(node.isType(['foo', 'bar'])); // true - * ``` - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -Node.prototype.isType = function(type) { - return utils.isType(this, type); -}; - -/** - * Return true if the `node.nodes` has the given `type`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.push(bar); - * - * cosole.log(foo.hasType('qux')); // false - * cosole.log(foo.hasType(/^(qux|bar)$/)); // true - * cosole.log(foo.hasType(['qux', 'bar'])); // true - * ``` - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -Node.prototype.hasType = function(type) { - return utils.hasType(this, type); -}; - -/** - * Get the siblings array, or `null` if it doesn't exist. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(bar.siblings.length) // 2 - * console.log(baz.siblings.length) // 2 - * ``` - * @return {Array} - * @api public - */ - -Object.defineProperty(Node.prototype, 'siblings', { - set: function() { - throw new Error('node.siblings is a getter and cannot be defined'); - }, - get: function() { - return this.parent ? this.parent.nodes : null; - } -}); - -/** - * Get the node's current index from `node.parent.nodes`. - * This should always be correct, even when the parent adds nodes. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.unshift(qux); - * - * console.log(bar.index) // 1 - * console.log(baz.index) // 2 - * console.log(qux.index) // 0 - * ``` - * @return {Number} - * @api public - */ - -Object.defineProperty(Node.prototype, 'index', { - set: function(index) { - define(this, 'idx', index); - }, - get: function() { - if (!Array.isArray(this.siblings)) { - return -1; - } - var tok = this.idx !== -1 ? this.siblings[this.idx] : null; - if (tok !== this) { - this.idx = this.siblings.indexOf(this); - } - return this.idx; - } -}); - -/** - * Get the previous node from the siblings array or `null`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(baz.prev.type) // 'bar' - * ``` - * @return {Object} - * @api public - */ - -Object.defineProperty(Node.prototype, 'prev', { - set: function() { - throw new Error('node.prev is a getter and cannot be defined'); - }, - get: function() { - if (Array.isArray(this.siblings)) { - return this.siblings[this.index - 1] || this.parent.prev; - } - return null; - } -}); - -/** - * Get the siblings array, or `null` if it doesn't exist. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(bar.siblings.length) // 2 - * console.log(baz.siblings.length) // 2 - * ``` - * @return {Object} - * @api public - */ - -Object.defineProperty(Node.prototype, 'next', { - set: function() { - throw new Error('node.next is a getter and cannot be defined'); - }, - get: function() { - if (Array.isArray(this.siblings)) { - return this.siblings[this.index + 1] || this.parent.next; - } - return null; - } -}); - -/** - * Get the first node from `node.nodes`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); - * - * console.log(foo.first.type) // 'bar' - * ``` - * @return {Object} The first node, or undefiend - * @api public - */ - -Object.defineProperty(Node.prototype, 'first', { - get: function() { - return this.nodes ? this.nodes[0] : null; - } -}); - -/** - * Get the last node from `node.nodes`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); - * - * console.log(foo.last.type) // 'qux' - * ``` - * @return {Object} The last node, or undefiend - * @api public - */ - -Object.defineProperty(Node.prototype, 'last', { - get: function() { - return this.nodes ? utils.last(this.nodes) : null; - } -}); - -/** - * Get the last node from `node.nodes`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); - * - * console.log(foo.last.type) // 'qux' - * ``` - * @return {Object} The last node, or undefiend - * @api public - */ - -Object.defineProperty(Node.prototype, 'scope', { - get: function() { - if (this.isScope !== true) { - return this.parent ? this.parent.scope : this; - } - return this; - } -}); - -/** - * Get own property names from Node prototype, but only the - * first time `Node` is instantiated - */ - -function lazyKeys() { - if (!ownNames) { - ownNames = Object.getOwnPropertyNames(Node.prototype); - } -} - -/** - * Simplified assertion. Throws an error is `val` is falsey. - */ - -function assert(val, message) { - if (!val) throw new Error(message); -} - -/** - * Expose `Node` - */ - -exports = module.exports = Node; - - -/***/ }), -/* 615 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(591); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 616 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var typeOf = __webpack_require__(592); -var utils = module.exports; - -/** - * Returns true if the given value is a node. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(utils.isNode(node)); //=> true - * console.log(utils.isNode({})); //=> false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {Boolean} - * @api public - */ - -utils.isNode = function(node) { - return typeOf(node) === 'object' && node.isNode === true; -}; - -/** - * Emit an empty string for the given `node`. - * - * ```js - * // do nothing for beginning-of-string - * snapdragon.compiler.set('bos', utils.noop); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {undefined} - * @api public - */ - -utils.noop = function(node) { - append(this, '', node); -}; - -/** - * Appdend `node.val` to `compiler.output`, exactly as it was created - * by the parser. - * - * ```js - * snapdragon.compiler.set('text', utils.identity); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {undefined} - * @api public - */ - -utils.identity = function(node) { - append(this, node.val, node); -}; - -/** - * Previously named `.emit`, this method appends the given `val` - * to `compiler.output` for the given node. Useful when you know - * what value should be appended advance, regardless of the actual - * value of `node.val`. - * - * ```js - * snapdragon.compiler - * .set('i', function(node) { - * this.mapVisit(node); - * }) - * .set('i.open', utils.append('')) - * .set('i.close', utils.append('')) - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {Function} Returns a compiler middleware function. - * @api public - */ - -utils.append = function(val) { - return function(node) { - append(this, val, node); - }; -}; - -/** - * Used in compiler middleware, this onverts an AST node into - * an empty `text` node and deletes `node.nodes` if it exists. - * The advantage of this method is that, as opposed to completely - * removing the node, indices will not need to be re-calculated - * in sibling nodes, and nothing is appended to the output. - * - * ```js - * utils.toNoop(node); - * // convert `node.nodes` to the given value instead of deleting it - * utils.toNoop(node, []); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Array} `nodes` Optionally pass a new `nodes` value, to replace the existing `node.nodes` array. - * @api public - */ - -utils.toNoop = function(node, nodes) { - if (nodes) { - node.nodes = nodes; - } else { - delete node.nodes; - node.type = 'text'; - node.val = ''; - } -}; - -/** - * Visit `node` with the given `fn`. The built-in `.visit` method in snapdragon - * automatically calls registered compilers, this allows you to pass a visitor - * function. - * - * ```js - * snapdragon.compiler.set('i', function(node) { - * utils.visit(node, function(childNode) { - * // do stuff with "childNode" - * return childNode; - * }); - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `fn` - * @return {Object} returns the node after recursively visiting all child nodes. - * @api public - */ - -utils.visit = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(fn), 'expected a visitor function'); - fn(node); - return node.nodes ? utils.mapVisit(node, fn) : node; -}; - -/** - * Map [visit](#visit) the given `fn` over `node.nodes`. This is called by - * [visit](#visit), use this method if you do not want `fn` to be called on - * the first node. - * - * ```js - * snapdragon.compiler.set('i', function(node) { - * utils.mapVisit(node, function(childNode) { - * // do stuff with "childNode" - * return childNode; - * }); - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Object} `options` - * @param {Function} `fn` - * @return {Object} returns the node - * @api public - */ - -utils.mapVisit = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isArray(node.nodes), 'expected node.nodes to be an array'); - assert(isFunction(fn), 'expected a visitor function'); - - for (var i = 0; i < node.nodes.length; i++) { - utils.visit(node.nodes[i], fn); - } - return node; -}; - -/** - * Unshift an `*.open` node onto `node.nodes`. - * - * ```js - * var Node = require('snapdragon-node'); - * snapdragon.parser.set('brace', function(node) { - * var match = this.match(/^{/); - * if (match) { - * var parent = new Node({type: 'brace'}); - * utils.addOpen(parent, Node); - * console.log(parent.nodes[0]): - * // { type: 'brace.open', val: '' }; - * - * // push the parent "brace" node onto the stack - * this.push(parent); - * - * // return the parent node, so it's also added to the AST - * return brace; - * } - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the created opening node. - * @api public - */ - -utils.addOpen = function(node, Node, val, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - if (typeof val === 'function') { - filter = val; - val = ''; - } - - if (typeof filter === 'function' && !filter(node)) return; - var open = new Node({ type: node.type + '.open', val: val}); - var unshift = node.unshift || node.unshiftNode; - if (typeof unshift === 'function') { - unshift.call(node, open); - } else { - utils.unshiftNode(node, open); - } - return open; -}; - -/** - * Push a `*.close` node onto `node.nodes`. - * - * ```js - * var Node = require('snapdragon-node'); - * snapdragon.parser.set('brace', function(node) { - * var match = this.match(/^}/); - * if (match) { - * var parent = this.parent(); - * if (parent.type !== 'brace') { - * throw new Error('missing opening: ' + '}'); - * } - * - * utils.addClose(parent, Node); - * console.log(parent.nodes[parent.nodes.length - 1]): - * // { type: 'brace.close', val: '' }; - * - * // no need to return a node, since the parent - * // was already added to the AST - * return; - * } - * }); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the created closing node. - * @api public - */ - -utils.addClose = function(node, Node, val, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - if (typeof val === 'function') { - filter = val; - val = ''; - } - - if (typeof filter === 'function' && !filter(node)) return; - var close = new Node({ type: node.type + '.close', val: val}); - var push = node.push || node.pushNode; - if (typeof push === 'function') { - push.call(node, close); - } else { - utils.pushNode(node, close); - } - return close; -}; - -/** - * Wraps the given `node` with `*.open` and `*.close` nodes. - * - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the node - * @api public - */ - -utils.wrapNodes = function(node, Node, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - utils.addOpen(node, Node, filter); - utils.addClose(node, Node, filter); - return node; -}; - -/** - * Push the given `node` onto `parent.nodes`, and set `parent` as `node.parent. - * - * ```js - * var parent = new Node({type: 'foo'}); - * var node = new Node({type: 'bar'}); - * utils.pushNode(parent, node); - * console.log(parent.nodes[0].type) // 'bar' - * console.log(node.parent.type) // 'foo' - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Object} Returns the child node - * @api public - */ - -utils.pushNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - node.define('parent', parent); - parent.nodes = parent.nodes || []; - parent.nodes.push(node); - return node; -}; - -/** - * Unshift `node` onto `parent.nodes`, and set `parent` as `node.parent. - * - * ```js - * var parent = new Node({type: 'foo'}); - * var node = new Node({type: 'bar'}); - * utils.unshiftNode(parent, node); - * console.log(parent.nodes[0].type) // 'bar' - * console.log(node.parent.type) // 'foo' - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {undefined} - * @api public - */ - -utils.unshiftNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - node.define('parent', parent); - parent.nodes = parent.nodes || []; - parent.nodes.unshift(node); -}; - -/** - * Pop the last `node` off of `parent.nodes`. The advantage of - * using this method is that it checks for `node.nodes` and works - * with any version of `snapdragon-node`. - * - * ```js - * var parent = new Node({type: 'foo'}); - * utils.pushNode(parent, new Node({type: 'foo'})); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.popNode(parent); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. - * @api public - */ - -utils.popNode = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (typeof node.pop === 'function') { - return node.pop(); - } - return node.nodes && node.nodes.pop(); -}; - -/** - * Shift the first `node` off of `parent.nodes`. The advantage of - * using this method is that it checks for `node.nodes` and works - * with any version of `snapdragon-node`. - * - * ```js - * var parent = new Node({type: 'foo'}); - * utils.pushNode(parent, new Node({type: 'foo'})); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.shiftNode(parent); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. - * @api public - */ - -utils.shiftNode = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (typeof node.shift === 'function') { - return node.shift(); - } - return node.nodes && node.nodes.shift(); -}; - -/** - * Remove the specified `node` from `parent.nodes`. - * - * ```js - * var parent = new Node({type: 'abc'}); - * var foo = new Node({type: 'foo'}); - * utils.pushNode(parent, foo); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.removeNode(parent, foo); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Object|undefined} Returns the removed node, if successful, or undefined if it does not exist on `parent.nodes`. - * @api public - */ - -utils.removeNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent.node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - if (!parent.nodes) { - return null; - } - - if (typeof parent.remove === 'function') { - return parent.remove(node); - } - - var idx = parent.nodes.indexOf(node); - if (idx !== -1) { - return parent.nodes.splice(idx, 1); - } -}; - -/** - * Returns true if `node.type` matches the given `type`. Throws a - * `TypeError` if `node` is not an instance of `Node`. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(utils.isType(node, 'foo')); // false - * console.log(utils.isType(node, 'bar')); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -utils.isType = function(node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - switch (typeOf(type)) { - case 'array': - var types = type.slice(); - for (var i = 0; i < types.length; i++) { - if (utils.isType(node, types[i])) { - return true; - } - } - return false; - case 'string': - return node.type === type; - case 'regexp': - return type.test(node.type); - default: { - throw new TypeError('expected "type" to be an array, string or regexp'); - } - } -}; - -/** - * Returns true if the given `node` has the given `type` in `node.nodes`. - * Throws a `TypeError` if `node` is not an instance of `Node`. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'bar'}), - * new Node({type: 'baz'}) - * ] - * }); - * console.log(utils.hasType(node, 'xyz')); // false - * console.log(utils.hasType(node, 'baz')); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -utils.hasType = function(node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (!Array.isArray(node.nodes)) return false; - for (var i = 0; i < node.nodes.length; i++) { - if (utils.isType(node.nodes[i], type)) { - return true; - } - } - return false; -}; - -/** - * Returns the first node from `node.nodes` of the given `type` - * - * ```js - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'text', val: 'abc'}), - * new Node({type: 'text', val: 'xyz'}) - * ] - * }); - * - * var textNode = utils.firstOfType(node.nodes, 'text'); - * console.log(textNode.val); - * //=> 'abc' - * ``` - * @param {Array} `nodes` - * @param {String} `type` - * @return {Object|undefined} Returns the first matching node or undefined. - * @api public - */ - -utils.firstOfType = function(nodes, type) { - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - if (utils.isType(node, type)) { - return node; - } - } -}; - -/** - * Returns the node at the specified index, or the first node of the - * given `type` from `node.nodes`. - * - * ```js - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'text', val: 'abc'}), - * new Node({type: 'text', val: 'xyz'}) - * ] - * }); - * - * var nodeOne = utils.findNode(node.nodes, 'text'); - * console.log(nodeOne.val); - * //=> 'abc' - * - * var nodeTwo = utils.findNode(node.nodes, 1); - * console.log(nodeTwo.val); - * //=> 'xyz' - * ``` - * - * @param {Array} `nodes` - * @param {String|Number} `type` Node type or index. - * @return {Object} Returns a node or undefined. - * @api public - */ - -utils.findNode = function(nodes, type) { - if (!Array.isArray(nodes)) { - return null; - } - if (typeof type === 'number') { - return nodes[type]; - } - return utils.firstOfType(nodes, type); -}; - -/** - * Returns true if the given node is an "*.open" node. - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * - * console.log(utils.isOpen(brace)); // false - * console.log(utils.isOpen(open)); // true - * console.log(utils.isOpen(close)); // false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.isOpen = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - return node.type.slice(-5) === '.open'; -}; - -/** - * Returns true if the given node is a "*.close" node. - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * - * console.log(utils.isClose(brace)); // false - * console.log(utils.isClose(open)); // false - * console.log(utils.isClose(close)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.isClose = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - return node.type.slice(-6) === '.close'; -}; - -/** - * Returns true if `node.nodes` **has** an `.open` node - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var open = new Node({type: 'brace.open'}); - * console.log(utils.hasOpen(brace)); // false - * - * brace.pushNode(open); - * console.log(utils.hasOpen(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.hasOpen = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - var first = node.first || node.nodes ? node.nodes[0] : null; - if (utils.isNode(first)) { - return first.type === node.type + '.open'; - } - return false; -}; - -/** - * Returns true if `node.nodes` **has** a `.close` node - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var close = new Node({type: 'brace.close'}); - * console.log(utils.hasClose(brace)); // false - * - * brace.pushNode(close); - * console.log(utils.hasClose(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.hasClose = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - var last = node.last || node.nodes ? node.nodes[node.nodes.length - 1] : null; - if (utils.isNode(last)) { - return last.type === node.type + '.close'; - } - return false; -}; - -/** - * Returns true if `node.nodes` has both `.open` and `.close` nodes - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * console.log(utils.hasOpen(brace)); // false - * console.log(utils.hasClose(brace)); // false - * - * brace.pushNode(open); - * brace.pushNode(close); - * console.log(utils.hasOpen(brace)); // true - * console.log(utils.hasClose(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ - -utils.hasOpenAndClose = function(node) { - return utils.hasOpen(node) && utils.hasClose(node); -}; - -/** - * Push the given `node` onto the `state.inside` array for the - * given type. This array is used as a specialized "stack" for - * only the given `node.type`. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * utils.addType(state, node); - * console.log(state.inside); - * //=> { brace: [{type: 'brace'}] } - * ``` - * @param {Object} `state` The `compiler.state` object or custom state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Array} Returns the `state.inside` stack for the given type. - * @api public - */ - -utils.addType = function(state, node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - - var type = node.parent - ? node.parent.type - : node.type.replace(/\.open$/, ''); - - if (!state.hasOwnProperty('inside')) { - state.inside = {}; - } - if (!state.inside.hasOwnProperty(type)) { - state.inside[type] = []; - } - - var arr = state.inside[type]; - arr.push(node); - return arr; -}; - -/** - * Remove the given `node` from the `state.inside` array for the - * given type. This array is used as a specialized "stack" for - * only the given `node.type`. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * utils.addType(state, node); - * console.log(state.inside); - * //=> { brace: [{type: 'brace'}] } - * utils.removeType(state, node); - * //=> { brace: [] } - * ``` - * @param {Object} `state` The `compiler.state` object or custom state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Array} Returns the `state.inside` stack for the given type. - * @api public - */ - -utils.removeType = function(state, node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - - var type = node.parent - ? node.parent.type - : node.type.replace(/\.close$/, ''); - - if (state.inside.hasOwnProperty(type)) { - return state.inside[type].pop(); - } -}; - -/** - * Returns true if `node.val` is an empty string, or `node.nodes` does - * not contain any non-empty text nodes. - * - * ```js - * var node = new Node({type: 'text'}); - * utils.isEmpty(node); //=> true - * node.val = 'foo'; - * utils.isEmpty(node); //=> false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `fn` - * @return {Boolean} - * @api public - */ - -utils.isEmpty = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - - if (!Array.isArray(node.nodes)) { - if (node.type !== 'text') { - return true; - } - if (typeof fn === 'function') { - return fn(node, node.parent); - } - return !utils.trim(node.val); - } - - for (var i = 0; i < node.nodes.length; i++) { - var child = node.nodes[i]; - if (utils.isOpen(child) || utils.isClose(child)) { - continue; - } - if (!utils.isEmpty(child, fn)) { - return false; - } - } - - return true; -}; - -/** - * Returns true if the `state.inside` stack for the given type exists - * and has one or more nodes on it. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * console.log(utils.isInsideType(state, 'brace')); //=> false - * utils.addType(state, node); - * console.log(utils.isInsideType(state, 'brace')); //=> true - * utils.removeType(state, node); - * console.log(utils.isInsideType(state, 'brace')); //=> false - * ``` - * @param {Object} `state` - * @param {String} `type` - * @return {Boolean} - * @api public - */ - -utils.isInsideType = function(state, type) { - assert(isObject(state), 'expected state to be an object'); - assert(isString(type), 'expected type to be a string'); - - if (!state.hasOwnProperty('inside')) { - return false; - } - - if (!state.inside.hasOwnProperty(type)) { - return false; - } - - return state.inside[type].length > 0; -}; - -/** - * Returns true if `node` is either a child or grand-child of the given `type`, - * or `state.inside[type]` is a non-empty array. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * console.log(utils.isInside(state, open, 'brace')); //=> false - * utils.pushNode(node, open); - * console.log(utils.isInside(state, open, 'brace')); //=> true - * ``` - * @param {Object} `state` Either the `compiler.state` object, if it exists, or a user-supplied state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` The `node.type` to check for. - * @return {Boolean} - * @api public - */ - -utils.isInside = function(state, node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - - if (Array.isArray(type)) { - for (var i = 0; i < type.length; i++) { - if (utils.isInside(state, node, type[i])) { - return true; - } - } - return false; - } - - var parent = node.parent; - if (typeof type === 'string') { - return (parent && parent.type === type) || utils.isInsideType(state, type); - } - - if (typeOf(type) === 'regexp') { - if (parent && parent.type && type.test(parent.type)) { - return true; - } - - var keys = Object.keys(state.inside); - var len = keys.length; - var idx = -1; - while (++idx < len) { - var key = keys[idx]; - var val = state.inside[key]; - - if (Array.isArray(val) && val.length !== 0 && type.test(key)) { - return true; - } - } - } - return false; -}; - -/** - * Get the last `n` element from the given `array`. Used for getting - * a node from `node.nodes.` - * - * @param {Array} `array` - * @param {Number} `n` - * @return {undefined} - * @api public - */ - -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - -/** - * Cast the given `val` to an array. - * - * ```js - * console.log(utils.arrayify('')); - * //=> [] - * console.log(utils.arrayify('foo')); - * //=> ['foo'] - * console.log(utils.arrayify(['foo'])); - * //=> ['foo'] - * ``` - * @param {any} `val` - * @return {Array} - * @api public - */ - -utils.arrayify = function(val) { - if (typeof val === 'string' && val !== '') { - return [val]; - } - if (!Array.isArray(val)) { - return []; - } - return val; -}; - -/** - * Convert the given `val` to a string by joining with `,`. Useful - * for creating a cheerio/CSS/DOM-style selector from a list of strings. - * - * @param {any} `val` - * @return {Array} - * @api public - */ - -utils.stringify = function(val) { - return utils.arrayify(val).join(','); -}; - -/** - * Ensure that the given value is a string and call `.trim()` on it, - * or return an empty string. - * - * @param {String} `str` - * @return {String} - * @api public - */ - -utils.trim = function(str) { - return typeof str === 'string' ? str.trim() : ''; -}; - -/** - * Return true if val is an object - */ - -function isObject(val) { - return typeOf(val) === 'object'; -} - -/** - * Return true if val is a string - */ - -function isString(val) { - return typeof val === 'string'; -} - -/** - * Return true if val is a function - */ - -function isFunction(val) { - return typeof val === 'function'; -} - -/** - * Return true if val is an array - */ - -function isArray(val) { - return Array.isArray(val); -} - -/** - * Shim to ensure the `.append` methods work with any version of snapdragon - */ - -function append(compiler, val, node) { - if (typeof compiler.append !== 'function') { - return compiler.emit(val, node); - } - return compiler.append(val, node); -} - -/** - * Simplified assertion. Throws an error is `val` is falsey. - */ - -function assert(val, message) { - if (!val) throw new Error(message); -} - - -/***/ }), -/* 617 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var extend = __webpack_require__(601); -var Snapdragon = __webpack_require__(618); -var compilers = __webpack_require__(603); -var parsers = __webpack_require__(613); -var utils = __webpack_require__(604); - -/** - * Customize Snapdragon parser and renderer - */ - -function Braces(options) { - this.options = extend({}, options); -} - -/** - * Initialize braces - */ - -Braces.prototype.init = function(options) { - if (this.isInitialized) return; - this.isInitialized = true; - var opts = utils.createOptions({}, this.options, options); - this.snapdragon = this.options.snapdragon || new Snapdragon(opts); - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; - - compilers(this.snapdragon, opts); - parsers(this.snapdragon, opts); - - /** - * Call Snapdragon `.parse` method. When AST is returned, we check to - * see if any unclosed braces are left on the stack and, if so, we iterate - * over the stack and correct the AST so that compilers are called in the correct - * order and unbalance braces are properly escaped. - */ - - utils.define(this.snapdragon, 'parse', function(pattern, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - this.parser.ast.input = pattern; - - var stack = this.parser.stack; - while (stack.length) { - addParent({type: 'brace.close', val: ''}, stack.pop()); - } - - function addParent(node, parent) { - utils.define(node, 'parent', parent); - parent.nodes.push(node); - } - - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); -}; - -/** - * Decorate `.parse` method - */ - -Braces.prototype.parse = function(ast, options) { - if (ast && typeof ast === 'object' && ast.nodes) return ast; - this.init(options); - return this.snapdragon.parse(ast, options); -}; - -/** - * Decorate `.compile` method - */ - -Braces.prototype.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = this.parse(ast, options); - } else { - this.init(options); - } - return this.snapdragon.compile(ast, options); -}; - -/** - * Expand - */ - -Braces.prototype.expand = function(pattern) { - var ast = this.parse(pattern, {expand: true}); - return this.compile(ast, {expand: true}); -}; - -/** - * Optimize - */ - -Braces.prototype.optimize = function(pattern) { - var ast = this.parse(pattern, {optimize: true}); - return this.compile(ast, {optimize: true}); -}; - -/** - * Expose `Braces` - */ - -module.exports = Braces; - - -/***/ }), -/* 618 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var Base = __webpack_require__(619); -var define = __webpack_require__(645); -var Compiler = __webpack_require__(652); -var Parser = __webpack_require__(681); -var utils = __webpack_require__(660); -var regexCache = {}; -var cache = {}; - -/** - * Create a new instance of `Snapdragon` with the given `options`. - * - * ```js - * var snapdragon = new Snapdragon(); - * ``` - * - * @param {Object} `options` - * @api public - */ - -function Snapdragon(options) { - Base.call(this, null, options); - this.options = utils.extend({source: 'string'}, this.options); - this.compiler = new Compiler(this.options); - this.parser = new Parser(this.options); - - Object.defineProperty(this, 'compilers', { - get: function() { - return this.compiler.compilers; - } - }); - - Object.defineProperty(this, 'parsers', { - get: function() { - return this.parser.parsers; - } - }); - - Object.defineProperty(this, 'regex', { - get: function() { - return this.parser.regex; - } - }); -} - -/** - * Inherit Base - */ - -Base.extend(Snapdragon); - -/** - * Add a parser to `snapdragon.parsers` for capturing the given `type` using - * the specified regex or parser function. A function is useful if you need - * to customize how the token is created and/or have access to the parser - * instance to check options, etc. - * - * ```js - * snapdragon - * .capture('slash', /^\//) - * .capture('dot', function() { - * var pos = this.position(); - * var m = this.match(/^\./); - * if (!m) return; - * return pos({ - * type: 'dot', - * val: m[0] - * }); - * }); - * ``` - * @param {String} `type` - * @param {RegExp|Function} `regex` - * @return {Object} Returns the parser instance for chaining - * @api public - */ - -Snapdragon.prototype.capture = function() { - return this.parser.capture.apply(this.parser, arguments); -}; - -/** - * Register a plugin `fn`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * snapdragon.use(function() { - * console.log(this); //<= snapdragon instance - * console.log(this.parser); //<= parser instance - * console.log(this.compiler); //<= compiler instance - * }); - * ``` - * @param {Object} `fn` - * @api public - */ - -Snapdragon.prototype.use = function(fn) { - fn.call(this, this); - return this; -}; - -/** - * Parse the given `str`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * // register parsers - * snapdragon.parser.use(function() {}); - * - * // parse - * var ast = snapdragon.parse('foo/bar'); - * console.log(ast); - * ``` - * @param {String} `str` - * @param {Object} `options` Set `options.sourcemap` to true to enable source maps. - * @return {Object} Returns an AST. - * @api public - */ - -Snapdragon.prototype.parse = function(str, options) { - this.options = utils.extend({}, this.options, options); - var parsed = this.parser.parse(str, this.options); - - // add non-enumerable parser reference - define(parsed, 'parser', this.parser); - return parsed; -}; - -/** - * Compile the given `AST`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * // register plugins - * snapdragon.use(function() {}); - * // register parser plugins - * snapdragon.parser.use(function() {}); - * // register compiler plugins - * snapdragon.compiler.use(function() {}); - * - * // parse - * var ast = snapdragon.parse('foo/bar'); - * - * // compile - * var res = snapdragon.compile(ast); - * console.log(res.output); - * ``` - * @param {Object} `ast` - * @param {Object} `options` - * @return {Object} Returns an object with an `output` property with the rendered string. - * @api public - */ - -Snapdragon.prototype.compile = function(ast, options) { - this.options = utils.extend({}, this.options, options); - var compiled = this.compiler.compile(ast, this.options); - - // add non-enumerable compiler reference - define(compiled, 'compiler', this.compiler); - return compiled; -}; - -/** - * Expose `Snapdragon` - */ - -module.exports = Snapdragon; - -/** - * Expose `Parser` and `Compiler` - */ - -module.exports.Compiler = Compiler; -module.exports.Parser = Parser; - - -/***/ }), -/* 619 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var util = __webpack_require__(112); -var define = __webpack_require__(620); -var CacheBase = __webpack_require__(621); -var Emitter = __webpack_require__(622); -var isObject = __webpack_require__(590); -var merge = __webpack_require__(640); -var pascal = __webpack_require__(643); -var cu = __webpack_require__(644); - -/** - * Optionally define a custom `cache` namespace to use. - */ - -function namespace(name) { - var Cache = name ? CacheBase.namespace(name) : CacheBase; - var fns = []; - - /** - * Create an instance of `Base` with the given `config` and `options`. - * - * ```js - * // initialize with `config` and `options` - * var app = new Base({isApp: true}, {abc: true}); - * app.set('foo', 'bar'); - * - * // values defined with the given `config` object will be on the root of the instance - * console.log(app.baz); //=> undefined - * console.log(app.foo); //=> 'bar' - * // or use `.get` - * console.log(app.get('isApp')); //=> true - * console.log(app.get('foo')); //=> 'bar' - * - * // values defined with the given `options` object will be on `app.options - * console.log(app.options.abc); //=> true - * ``` - * - * @param {Object} `config` If supplied, this object is passed to [cache-base][] to merge onto the the instance upon instantiation. - * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object. - * @api public - */ - - function Base(config, options) { - if (!(this instanceof Base)) { - return new Base(config, options); - } - Cache.call(this, config); - this.is('base'); - this.initBase(config, options); - } - - /** - * Inherit cache-base - */ - - util.inherits(Base, Cache); - - /** - * Add static emitter methods - */ - - Emitter(Base); - - /** - * Initialize `Base` defaults with the given `config` object - */ - - Base.prototype.initBase = function(config, options) { - this.options = merge({}, this.options, options); - this.cache = this.cache || {}; - this.define('registered', {}); - if (name) this[name] = {}; - - // make `app._callbacks` non-enumerable - this.define('_callbacks', this._callbacks); - if (isObject(config)) { - this.visit('set', config); - } - Base.run(this, 'use', fns); - }; - - /** - * Set the given `name` on `app._name` and `app.is*` properties. Used for doing - * lookups in plugins. - * - * ```js - * app.is('foo'); - * console.log(app._name); - * //=> 'foo' - * console.log(app.isFoo); - * //=> true - * app.is('bar'); - * console.log(app.isFoo); - * //=> true - * console.log(app.isBar); - * //=> true - * console.log(app._name); - * //=> 'bar' - * ``` - * @name .is - * @param {String} `name` - * @return {Boolean} - * @api public - */ - - Base.prototype.is = function(name) { - if (typeof name !== 'string') { - throw new TypeError('expected name to be a string'); - } - this.define('is' + pascal(name), true); - this.define('_name', name); - this.define('_appname', name); - return this; - }; - - /** - * Returns true if a plugin has already been registered on an instance. - * - * Plugin implementors are encouraged to use this first thing in a plugin - * to prevent the plugin from being called more than once on the same - * instance. - * - * ```js - * var base = new Base(); - * base.use(function(app) { - * if (app.isRegistered('myPlugin')) return; - * // do stuff to `app` - * }); - * - * // to also record the plugin as being registered - * base.use(function(app) { - * if (app.isRegistered('myPlugin', true)) return; - * // do stuff to `app` - * }); - * ``` - * @name .isRegistered - * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once. - * @param {String} `name` The plugin name. - * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument. - * @return {Boolean} Returns true if a plugin is already registered. - * @api public - */ - - Base.prototype.isRegistered = function(name, register) { - if (this.registered.hasOwnProperty(name)) { - return true; - } - if (register !== false) { - this.registered[name] = true; - this.emit('plugin', name); - } - return false; - }; - - /** - * Define a plugin function to be called immediately upon init. Plugins are chainable - * and expose the following arguments to the plugin function: - * - * - `app`: the current instance of `Base` - * - `base`: the [first ancestor instance](#base) of `Base` - * - * ```js - * var app = new Base() - * .use(foo) - * .use(bar) - * .use(baz) - * ``` - * @name .use - * @param {Function} `fn` plugin function to call - * @return {Object} Returns the item instance for chaining. - * @api public - */ - - Base.prototype.use = function(fn) { - fn.call(this, this); - return this; - }; - - /** - * The `.define` method is used for adding non-enumerable property on the instance. - * Dot-notation is **not supported** with `define`. - * - * ```js - * // arbitrary `render` function using lodash `template` - * app.define('render', function(str, locals) { - * return _.template(str)(locals); - * }); - * ``` - * @name .define - * @param {String} `key` The name of the property to define. - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Base.prototype.define = function(key, val) { - if (isObject(key)) { - return this.visit('define', key); - } - define(this, key, val); - return this; - }; - - /** - * Mix property `key` onto the Base prototype. If base is inherited using - * `Base.extend` this method will be overridden by a new `mixin` method that will - * only add properties to the prototype of the inheriting application. - * - * ```js - * app.mixin('foo', function() { - * // do stuff - * }); - * ``` - * @name .mixin - * @param {String} `key` - * @param {Object|Array} `val` - * @return {Object} Returns the `base` instance for chaining. - * @api public - */ - - Base.prototype.mixin = function(key, val) { - Base.prototype[key] = val; - return this; - }; - - /** - * Non-enumberable mixin array, used by the static [Base.mixin]() method. - */ - - Base.prototype.mixins = Base.prototype.mixins || []; - - /** - * Getter/setter used when creating nested instances of `Base`, for storing a reference - * to the first ancestor instance. This works by setting an instance of `Base` on the `parent` - * property of a "child" instance. The `base` property defaults to the current instance if - * no `parent` property is defined. - * - * ```js - * // create an instance of `Base`, this is our first ("base") instance - * var first = new Base(); - * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later - * - * // create another instance - * var second = new Base(); - * // create a reference to the first instance (`first`) - * second.parent = first; - * - * // create another instance - * var third = new Base(); - * // create a reference to the previous instance (`second`) - * // repeat this pattern every time a "child" instance is created - * third.parent = second; - * - * // we can always access the first instance using the `base` property - * console.log(first.base.foo); - * //=> 'bar' - * console.log(second.base.foo); - * //=> 'bar' - * console.log(third.base.foo); - * //=> 'bar' - * // and now you know how to get to third base ;) - * ``` - * @name .base - * @api public - */ - - Object.defineProperty(Base.prototype, 'base', { - configurable: true, - get: function() { - return this.parent ? this.parent.base : this; - } - }); - - /** - * Static method for adding global plugin functions that will - * be added to an instance when created. - * - * ```js - * Base.use(function(app) { - * app.foo = 'bar'; - * }); - * var app = new Base(); - * console.log(app.foo); - * //=> 'bar' - * ``` - * @name #use - * @param {Function} `fn` Plugin function to use on each instance. - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'use', function(fn) { - fns.push(fn); - return Base; - }); - - /** - * Run an array of functions by passing each function - * to a method on the given object specified by the given property. - * - * @param {Object} `obj` Object containing method to use. - * @param {String} `prop` Name of the method on the object to use. - * @param {Array} `arr` Array of functions to pass to the method. - */ - - define(Base, 'run', function(obj, prop, arr) { - var len = arr.length, i = 0; - while (len--) { - obj[prop](arr[i++]); - } - return Base; - }); - - /** - * Static method for inheriting the prototype and static methods of the `Base` class. - * This method greatly simplifies the process of creating inheritance-based applications. - * See [static-extend][] for more details. - * - * ```js - * var extend = cu.extend(Parent); - * Parent.extend(Child); - * - * // optional methods - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @name #extend - * @param {Function} `Ctor` constructor to extend - * @param {Object} `methods` Optional prototype properties to mix in. - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'extend', cu.extend(Base, function(Ctor, Parent) { - Ctor.prototype.mixins = Ctor.prototype.mixins || []; - - define(Ctor, 'mixin', function(fn) { - var mixin = fn(Ctor.prototype, Ctor); - if (typeof mixin === 'function') { - Ctor.prototype.mixins.push(mixin); - } - return Ctor; - }); - - define(Ctor, 'mixins', function(Child) { - Base.run(Child, 'mixin', Ctor.prototype.mixins); - return Ctor; - }); - - Ctor.prototype.mixin = function(key, value) { - Ctor.prototype[key] = value; - return this; - }; - return Base; - })); - - /** - * Used for adding methods to the `Base` prototype, and/or to the prototype of child instances. - * When a mixin function returns a function, the returned function is pushed onto the `.mixins` - * array, making it available to be used on inheriting classes whenever `Base.mixins()` is - * called (e.g. `Base.mixins(Child)`). - * - * ```js - * Base.mixin(function(proto) { - * proto.foo = function(msg) { - * return 'foo ' + msg; - * }; - * }); - * ``` - * @name #mixin - * @param {Function} `fn` Function to call - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'mixin', function(fn) { - var mixin = fn(Base.prototype, Base); - if (typeof mixin === 'function') { - Base.prototype.mixins.push(mixin); - } - return Base; - }); - - /** - * Static method for running global mixin functions against a child constructor. - * Mixins must be registered before calling this method. - * - * ```js - * Base.extend(Child); - * Base.mixins(Child); - * ``` - * @name #mixins - * @param {Function} `Child` Constructor function of a child class - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'mixins', function(Child) { - Base.run(Child, 'mixin', Base.prototype.mixins); - return Base; - }); - - /** - * Similar to `util.inherit`, but copies all static properties, prototype properties, and - * getters/setters from `Provider` to `Receiver`. See [class-utils][]{#inherit} for more details. - * - * ```js - * Base.inherit(Foo, Bar); - * ``` - * @name #inherit - * @param {Function} `Receiver` Receiving (child) constructor - * @param {Function} `Provider` Providing (parent) constructor - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ - - define(Base, 'inherit', cu.inherit); - define(Base, 'bubble', cu.bubble); - return Base; -} - -/** - * Expose `Base` with default settings - */ - -module.exports = namespace(); - -/** - * Allow users to define a namespace - */ - -module.exports.namespace = namespace; - - -/***/ }), -/* 620 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(591); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 621 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(590); -var Emitter = __webpack_require__(622); -var visit = __webpack_require__(623); -var toPath = __webpack_require__(626); -var union = __webpack_require__(627); -var del = __webpack_require__(632); -var get = __webpack_require__(629); -var has = __webpack_require__(638); -var set = __webpack_require__(630); - -/** - * Create a `Cache` constructor that when instantiated will - * store values on the given `prop`. - * - * ```js - * var Cache = require('cache-base').namespace('data'); - * var cache = new Cache(); - * - * cache.set('foo', 'bar'); - * //=> {data: {foo: 'bar'}} - * ``` - * @param {String} `prop` The property name to use for storing values. - * @return {Function} Returns a custom `Cache` constructor - * @api public - */ - -function namespace(prop) { - - /** - * Create a new `Cache`. Internally the `Cache` constructor is created using - * the `namespace` function, with `cache` defined as the storage object. - * - * ```js - * var app = new Cache(); - * ``` - * @param {Object} `cache` Optionally pass an object to initialize with. - * @constructor - * @api public - */ - - function Cache(cache) { - if (prop) { - this[prop] = {}; - } - if (cache) { - this.set(cache); - } - } - - /** - * Inherit Emitter - */ - - Emitter(Cache.prototype); - - /** - * Assign `value` to `key`. Also emits `set` with - * the key and value. - * - * ```js - * app.on('set', function(key, val) { - * // do something when `set` is emitted - * }); - * - * app.set(key, value); - * - * // also takes an object or array - * app.set({name: 'Halle'}); - * app.set([{foo: 'bar'}, {baz: 'quux'}]); - * console.log(app); - * //=> {name: 'Halle', foo: 'bar', baz: 'quux'} - * ``` - * - * @name .set - * @emits `set` with `key` and `value` as arguments. - * @param {String} `key` - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.set = function(key, val) { - if (Array.isArray(key) && arguments.length === 2) { - key = toPath(key); - } - if (isObject(key) || Array.isArray(key)) { - this.visit('set', key); - } else { - set(prop ? this[prop] : this, key, val); - this.emit('set', key, val); - } - return this; - }; - - /** - * Union `array` to `key`. Also emits `set` with - * the key and value. - * - * ```js - * app.union('a.b', ['foo']); - * app.union('a.b', ['bar']); - * console.log(app.get('a')); - * //=> {b: ['foo', 'bar']} - * ``` - * @name .union - * @param {String} `key` - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.union = function(key, val) { - if (Array.isArray(key) && arguments.length === 2) { - key = toPath(key); - } - var ctx = prop ? this[prop] : this; - union(ctx, key, arrayify(val)); - this.emit('union', val); - return this; - }; - - /** - * Return the value of `key`. Dot notation may be used - * to get [nested property values][get-value]. - * - * ```js - * app.set('a.b.c', 'd'); - * app.get('a.b'); - * //=> {c: 'd'} - * - * app.get(['a', 'b']); - * //=> {c: 'd'} - * ``` - * - * @name .get - * @emits `get` with `key` and `value` as arguments. - * @param {String} `key` The name of the property to get. Dot-notation may be used. - * @return {any} Returns the value of `key` - * @api public - */ - - Cache.prototype.get = function(key) { - key = toPath(arguments); - - var ctx = prop ? this[prop] : this; - var val = get(ctx, key); - - this.emit('get', key, val); - return val; - }; - - /** - * Return true if app has a stored value for `key`, - * false only if value is `undefined`. - * - * ```js - * app.set('foo', 'bar'); - * app.has('foo'); - * //=> true - * ``` - * - * @name .has - * @emits `has` with `key` and true or false as arguments. - * @param {String} `key` - * @return {Boolean} - * @api public - */ - - Cache.prototype.has = function(key) { - key = toPath(arguments); - - var ctx = prop ? this[prop] : this; - var val = get(ctx, key); - - var has = typeof val !== 'undefined'; - this.emit('has', key, has); - return has; - }; - - /** - * Delete one or more properties from the instance. - * - * ```js - * app.del(); // delete all - * // or - * app.del('foo'); - * // or - * app.del(['foo', 'bar']); - * ``` - * @name .del - * @emits `del` with the `key` as the only argument. - * @param {String|Array} `key` Property name or array of property names. - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.del = function(key) { - if (Array.isArray(key)) { - this.visit('del', key); - } else { - del(prop ? this[prop] : this, key); - this.emit('del', key); - } - return this; - }; - - /** - * Reset the entire cache to an empty object. - * - * ```js - * app.clear(); - * ``` - * @api public - */ - - Cache.prototype.clear = function() { - if (prop) { - this[prop] = {}; - } - }; - - /** - * Visit `method` over the properties in the given object, or map - * visit over the object-elements in an array. - * - * @name .visit - * @param {String} `method` The name of the `base` method to call. - * @param {Object|Array} `val` The object or array to iterate over. - * @return {Object} Returns the instance for chaining. - * @api public - */ - - Cache.prototype.visit = function(method, val) { - visit(this, method, val); - return this; - }; - - return Cache; -} - -/** - * Cast val to an array - */ - -function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -} - -/** - * Expose `Cache` - */ - -module.exports = namespace(); - -/** - * Expose `Cache.namespace` - */ - -module.exports.namespace = namespace; - - -/***/ }), -/* 622 */ -/***/ (function(module, exports, __webpack_require__) { - - -/** - * Expose `Emitter`. - */ - -if (true) { - module.exports = Emitter; -} - -/** - * Initialize a new `Emitter`. - * - * @api public - */ - -function Emitter(obj) { - if (obj) return mixin(obj); -}; - -/** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private - */ - -function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; -} - -/** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.on = -Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks['$' + event] = this._callbacks['$' + event] || []) - .push(fn); - return this; -}; - -/** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.once = function(event, fn){ - function on() { - this.off(event, on); - fn.apply(this, arguments); - } - - on.fn = fn; - this.on(event, on); - return this; -}; - -/** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.off = -Emitter.prototype.removeListener = -Emitter.prototype.removeAllListeners = -Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; - } - - // specific event - var callbacks = this._callbacks['$' + event]; - if (!callbacks) return this; - - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks['$' + event]; - return this; - } - - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } - } - - // Remove event specific arrays for event types that no - // one is subscribed for to avoid memory leak. - if (callbacks.length === 0) { - delete this._callbacks['$' + event]; - } - - return this; -}; - -/** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} - */ - -Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - - var args = new Array(arguments.length - 1) - , callbacks = this._callbacks['$' + event]; - - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); - } - } - - return this; -}; - -/** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public - */ - -Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks['$' + event] || []; -}; - -/** - * Check if this emitter has `event` handlers. - * - * @param {String} event - * @return {Boolean} - * @api public - */ - -Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; -}; - - -/***/ }), -/* 623 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * collection-visit - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var visit = __webpack_require__(624); -var mapVisit = __webpack_require__(625); - -module.exports = function(collection, method, val) { - var result; - - if (typeof val === 'string' && (method in collection)) { - var args = [].slice.call(arguments, 2); - result = collection[method].apply(collection, args); - } else if (Array.isArray(val)) { - result = mapVisit.apply(null, arguments); - } else { - result = visit.apply(null, arguments); - } - - if (typeof result !== 'undefined') { - return result; - } - - return collection; -}; - - -/***/ }), -/* 624 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * object-visit - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isObject = __webpack_require__(590); - -module.exports = function visit(thisArg, method, target, val) { - if (!isObject(thisArg) && typeof thisArg !== 'function') { - throw new Error('object-visit expects `thisArg` to be an object.'); - } - - if (typeof method !== 'string') { - throw new Error('object-visit expects `method` name to be a string'); - } - - if (typeof thisArg[method] !== 'function') { - return thisArg; - } - - var args = [].slice.call(arguments, 3); - target = target || {}; - - for (var key in target) { - var arr = [key, target[key]].concat(args); - thisArg[method].apply(thisArg, arr); - } - return thisArg; -}; - - -/***/ }), -/* 625 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var util = __webpack_require__(112); -var visit = __webpack_require__(624); - -/** - * Map `visit` over an array of objects. - * - * @param {Object} `collection` The context in which to invoke `method` - * @param {String} `method` Name of the method to call on `collection` - * @param {Object} `arr` Array of objects. - */ - -module.exports = function mapVisit(collection, method, val) { - if (isObject(val)) { - return visit.apply(null, arguments); - } - - if (!Array.isArray(val)) { - throw new TypeError('expected an array: ' + util.inspect(val)); - } - - var args = [].slice.call(arguments, 3); - - for (var i = 0; i < val.length; i++) { - var ele = val[i]; - if (isObject(ele)) { - visit.apply(null, [collection, method, ele].concat(args)); - } else { - collection[method].apply(collection, [ele].concat(args)); - } - } -}; - -function isObject(val) { - return val && (typeof val === 'function' || (!Array.isArray(val) && typeof val === 'object')); -} - - -/***/ }), -/* 626 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * to-object-path - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); - -module.exports = function toPath(args) { - if (typeOf(args) !== 'arguments') { - args = arguments; - } - return filter(args).join('.'); -}; - -function filter(arr) { - var len = arr.length; - var idx = -1; - var res = []; - - while (++idx < len) { - var ele = arr[idx]; - if (typeOf(ele) === 'arguments' || Array.isArray(ele)) { - res.push.apply(res, filter(ele)); - } else if (typeof ele === 'string') { - res.push(ele); - } - } - return res; -} - - -/***/ }), -/* 627 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(602); -var union = __webpack_require__(628); -var get = __webpack_require__(629); -var set = __webpack_require__(630); - -module.exports = function unionValue(obj, prop, value) { - if (!isObject(obj)) { - throw new TypeError('union-value expects the first argument to be an object.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('union-value expects `prop` to be a string.'); - } - - var arr = arrayify(get(obj, prop)); - set(obj, prop, union(arr, arrayify(value))); - return obj; -}; - -function arrayify(val) { - if (val === null || typeof val === 'undefined') { - return []; - } - if (Array.isArray(val)) { - return val; - } - return [val]; -} - - -/***/ }), -/* 628 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = function union(init) { - if (!Array.isArray(init)) { - throw new TypeError('arr-union expects the first argument to be an array.'); - } - - var len = arguments.length; - var i = 0; - - while (++i < len) { - var arg = arguments[i]; - if (!arg) continue; - - if (!Array.isArray(arg)) { - arg = [arg]; - } - - for (var j = 0; j < arg.length; j++) { - var ele = arg[j]; - - if (init.indexOf(ele) >= 0) { - continue; - } - init.push(ele); - } - } - return init; -}; - - -/***/ }), -/* 629 */ -/***/ (function(module, exports) { - -/*! - * get-value - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -module.exports = function(obj, prop, a, b, c) { - if (!isObject(obj) || !prop) { - return obj; - } - - prop = toString(prop); - - // allowing for multiple properties to be passed as - // a string or array, but much faster (3-4x) than doing - // `[].slice.call(arguments)` - if (a) prop += '.' + toString(a); - if (b) prop += '.' + toString(b); - if (c) prop += '.' + toString(c); - - if (prop in obj) { - return obj[prop]; - } - - var segs = prop.split('.'); - var len = segs.length; - var i = -1; - - while (obj && (++i < len)) { - var key = segs[i]; - while (key[key.length - 1] === '\\') { - key = key.slice(0, -1) + '.' + segs[++i]; - } - obj = obj[key]; - } - return obj; -}; - -function isObject(val) { - return val !== null && (typeof val === 'object' || typeof val === 'function'); -} - -function toString(val) { - if (!val) return ''; - if (Array.isArray(val)) { - return val.join('.'); - } - return val; -} - - -/***/ }), -/* 630 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * set-value - * - * Copyright (c) Jon Schlinkert (https://github.com/jonschlinkert). - * Released under the MIT License. - */ - - - -const { deleteProperty } = Reflect; -const isPrimitive = __webpack_require__(631); -const isPlainObject = __webpack_require__(597); - -const isObject = value => { - return (typeof value === 'object' && value !== null) || typeof value === 'function'; -}; - -const isUnsafeKey = key => { - return key === '__proto__' || key === 'constructor' || key === 'prototype'; -}; - -const validateKey = key => { - if (!isPrimitive(key)) { - throw new TypeError('Object keys must be strings or symbols'); - } - - if (isUnsafeKey(key)) { - throw new Error(`Cannot set unsafe key: "${key}"`); - } -}; - -const toStringKey = input => { - return Array.isArray(input) ? input.flat().map(String).join(',') : input; -}; - -const createMemoKey = (input, options) => { - if (typeof input !== 'string' || !options) return input; - let key = input + ';'; - if (options.arrays !== undefined) key += `arrays=${options.arrays};`; - if (options.separator !== undefined) key += `separator=${options.separator};`; - if (options.split !== undefined) key += `split=${options.split};`; - if (options.merge !== undefined) key += `merge=${options.merge};`; - if (options.preservePaths !== undefined) key += `preservePaths=${options.preservePaths};`; - return key; -}; - -const memoize = (input, options, fn) => { - const key = toStringKey(options ? createMemoKey(input, options) : input); - validateKey(key); - - const value = setValue.cache.get(key) || fn(); - setValue.cache.set(key, value); - return value; -}; - -const splitString = (input, options = {}) => { - const sep = options.separator || '.'; - const preserve = sep === '/' ? false : options.preservePaths; - - if (typeof input === 'string' && preserve !== false && /\//.test(input)) { - return [input]; - } - - const parts = []; - let part = ''; - - const push = part => { - let number; - if (part.trim() !== '' && Number.isInteger((number = Number(part)))) { - parts.push(number); - } else { - parts.push(part); - } - }; - - for (let i = 0; i < input.length; i++) { - const value = input[i]; - - if (value === '\\') { - part += input[++i]; - continue; - } - - if (value === sep) { - push(part); - part = ''; - continue; - } - - part += value; - } - - if (part) { - push(part); - } - - return parts; -}; - -const split = (input, options) => { - if (options && typeof options.split === 'function') return options.split(input); - if (typeof input === 'symbol') return [input]; - if (Array.isArray(input)) return input; - return memoize(input, options, () => splitString(input, options)); -}; - -const assignProp = (obj, prop, value, options) => { - validateKey(prop); - - // Delete property when "value" is undefined - if (value === undefined) { - deleteProperty(obj, prop); - - } else if (options && options.merge) { - const merge = options.merge === 'function' ? options.merge : Object.assign; - - // Only merge plain objects - if (merge && isPlainObject(obj[prop]) && isPlainObject(value)) { - obj[prop] = merge(obj[prop], value); - } else { - obj[prop] = value; - } - - } else { - obj[prop] = value; - } - - return obj; -}; - -const setValue = (target, path, value, options) => { - if (!path || !isObject(target)) return target; - - const keys = split(path, options); - let obj = target; - - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - const next = keys[i + 1]; - - validateKey(key); - - if (next === undefined) { - assignProp(obj, key, value, options); - break; - } - - if (typeof next === 'number' && !Array.isArray(obj[key])) { - obj = obj[key] = []; - continue; - } - - if (!isObject(obj[key])) { - obj[key] = {}; - } - - obj = obj[key]; - } - - return target; -}; - -setValue.split = split; -setValue.cache = new Map(); -setValue.clear = () => { - setValue.cache = new Map(); -}; - -module.exports = setValue; - - -/***/ }), -/* 631 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-primitive - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function isPrimitive(val) { - if (typeof val === 'object') { - return val === null; - } - return typeof val !== 'function'; -}; - - -/***/ }), -/* 632 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * unset-value - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isObject = __webpack_require__(633); -var has = __webpack_require__(634); - -const isUnsafeKey = key => { - return key === '__proto__' || key === 'constructor' || key === 'prototype'; -}; - -const validateKey = key => { - if (isUnsafeKey(key)) { - throw new Error(`Cannot set unsafe key: "${key}"`); - } -}; - -module.exports = function unset(obj, prop) { - if (!isObject(obj)) { - throw new TypeError('expected an object.'); - } - - var isArray = Array.isArray(prop); - - if (!isArray && obj.hasOwnProperty(prop)) { - delete obj[prop]; - return true; - } - - if (has(obj, prop)) { - var segs = isArray ? prop.slice() : prop.split('.'); - var last = segs.pop(); - while (segs.length && segs[segs.length - 1].slice(-1) === '\\') { - last = segs.pop().slice(0, -1) + '.' + last; - } - while (segs.length) { - prop = segs.shift(); - validateKey(prop); - obj = obj[prop]; - } - return (delete obj[last]); - } - return true; -}; - - -/***/ }), -/* 633 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return isObject; }); -/*! - * isobject - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - -function isObject(val) { - return val != null && typeof val === 'object' && Array.isArray(val) === false; -}; - - -/***/ }), -/* 634 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-value - * - * Copyright (c) 2014-2018, Jon Schlinkert. - * Released under the MIT License. - */ - - - -const get = __webpack_require__(635); -const has = __webpack_require__(637); - -module.exports = function(obj, path, options) { - if (isObject(obj) && (typeof path === 'string' || Array.isArray(path))) { - return has(get(obj, path, options)); - } - return false; -}; - -function isObject(val) { - return val != null && (typeof val === 'object' || typeof val === 'function' || Array.isArray(val)); -} - - -/***/ }), -/* 635 */ -/***/ (function(module, exports, __webpack_require__) { - -/*! - * get-value - * - * Copyright (c) 2014-2018, Jon Schlinkert. - * Released under the MIT License. - */ - -const isObject = __webpack_require__(636); - -module.exports = function(target, path, options) { - if (!isObject(options)) { - options = { default: options }; - } - - if (!isValidObject(target)) { - return typeof options.default !== 'undefined' ? options.default : target; - } - - if (typeof path === 'number') { - path = String(path); - } - - const isArray = Array.isArray(path); - const isString = typeof path === 'string'; - const splitChar = options.separator || '.'; - const joinChar = options.joinChar || (typeof splitChar === 'string' ? splitChar : '.'); - - if (!isString && !isArray) { - return target; - } - - if (isString && path in target) { - return isValid(path, target, options) ? target[path] : options.default; - } - - let segs = isArray ? path : split(path, splitChar, options); - let len = segs.length; - let idx = 0; - - do { - let prop = segs[idx]; - if (typeof prop === 'number') { - prop = String(prop); - } - - while (prop && prop.slice(-1) === '\\') { - prop = join([prop.slice(0, -1), segs[++idx] || ''], joinChar, options); - } - - if (prop in target) { - if (!isValid(prop, target, options)) { - return options.default; - } - - target = target[prop]; - } else { - let hasProp = false; - let n = idx + 1; - - while (n < len) { - prop = join([prop, segs[n++]], joinChar, options); - - if ((hasProp = prop in target)) { - if (!isValid(prop, target, options)) { - return options.default; - } - - target = target[prop]; - idx = n - 1; - break; - } - } - - if (!hasProp) { - return options.default; - } - } - } while (++idx < len && isValidObject(target)); - - if (idx === len) { - return target; - } - - return options.default; -}; - -function join(segs, joinChar, options) { - if (typeof options.join === 'function') { - return options.join(segs); - } - return segs[0] + joinChar + segs[1]; -} - -function split(path, splitChar, options) { - if (typeof options.split === 'function') { - return options.split(path); - } - return path.split(splitChar); -} - -function isValid(key, target, options) { - if (typeof options.isValid === 'function') { - return options.isValid(key, target); - } - return true; -} - -function isValidObject(val) { - return isObject(val) || Array.isArray(val) || typeof val === 'function'; -} - - -/***/ }), -/* 636 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * isobject - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function isObject(val) { - return val != null && typeof val === 'object' && Array.isArray(val) === false; -}; - - -/***/ }), -/* 637 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-values - * - * Copyright (c) 2014-2018, Jon Schlinkert. - * Released under the MIT License. - */ - - - -const typeOf = __webpack_require__(592); - -module.exports = function has(val) { - switch (typeOf(val)) { - case 'boolean': - case 'date': - case 'function': - case 'null': - case 'number': - return true; - case 'undefined': - return false; - case 'regexp': - return val.source !== '(?:)' && val.source !== ''; - case 'buffer': - return val.toString() !== ''; - case 'error': - return val.message !== ''; - case 'string': - case 'arguments': - return val.length !== 0; - case 'file': - case 'map': - case 'set': - return val.size !== 0; - case 'array': - case 'object': - for (const key of Object.keys(val)) { - if (has(val[key])) { - return true; - } - } - return false; - - // everything else - default: { - return true; - } - } -}; - - -/***/ }), -/* 638 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-value - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isObject = __webpack_require__(590); -var hasValues = __webpack_require__(639); -var get = __webpack_require__(629); - -module.exports = function(val, prop) { - return hasValues(isObject(val) && prop ? get(val, prop) : val); -}; - - -/***/ }), -/* 639 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-values - * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); -var isNumber = __webpack_require__(608); - -module.exports = function hasValue(val) { - // is-number checks for NaN and other edge cases - if (isNumber(val)) { - return true; - } - - switch (typeOf(val)) { - case 'null': - case 'boolean': - case 'function': - return true; - case 'string': - case 'arguments': - return val.length !== 0; - case 'error': - return val.message !== ''; - case 'array': - var len = val.length; - if (len === 0) { - return false; - } - for (var i = 0; i < len; i++) { - if (hasValue(val[i])) { - return true; - } - } - return false; - case 'file': - case 'map': - case 'set': - return val.size !== 0; - case 'object': - var keys = Object.keys(val); - if (keys.length === 0) { - return false; - } - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (hasValue(val[key])) { - return true; - } - } - return false; - default: { - return false; - } - } -}; - - -/***/ }), -/* 640 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(641); -var forIn = __webpack_require__(642); - -function mixinDeep(target, objects) { - var len = arguments.length, i = 0; - while (++i < len) { - var obj = arguments[i]; - if (isObject(obj)) { - forIn(obj, copy, target); - } - } - return target; -} - -/** - * Copy properties from the source object to the - * target object. - * - * @param {*} `val` - * @param {String} `key` - */ - -function copy(val, key) { - if (!isValidKey(key)) { - return; - } - - var obj = this[key]; - if (isObject(val) && isObject(obj)) { - mixinDeep(obj, val); - } else { - this[key] = val; - } -} - -/** - * Returns true if `val` is an object or function. - * - * @param {any} val - * @return {Boolean} - */ - -function isObject(val) { - return isExtendable(val) && !Array.isArray(val); -} - -/** - * Returns true if `key` is a valid key to use when extending objects. - * - * @param {String} `key` - * @return {Boolean} - */ - -function isValidKey(key) { - return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; -}; - -/** - * Expose `mixinDeep` - */ - -module.exports = mixinDeep; - - -/***/ }), -/* 641 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isPlainObject = __webpack_require__(597); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; - - -/***/ }), -/* 642 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * for-in - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function forIn(obj, fn, thisArg) { - for (var key in obj) { - if (fn.call(thisArg, obj[key], key, obj) === false) { - break; - } - } -}; - - -/***/ }), -/* 643 */ -/***/ (function(module, exports) { - -/*! - * pascalcase - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -function pascalcase(str) { - if (typeof str !== 'string') { - throw new TypeError('expected a string.'); - } - str = str.replace(/([A-Z])/g, ' $1'); - if (str.length === 1) { return str.toUpperCase(); } - str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); - str = str.charAt(0).toUpperCase() + str.slice(1); - return str.replace(/[\W_]+(\w|$)/g, function (_, ch) { - return ch.toUpperCase(); - }); -} - -module.exports = pascalcase; - - -/***/ }), -/* 644 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var util = __webpack_require__(112); -var union = __webpack_require__(628); -var define = __webpack_require__(645); -var staticExtend = __webpack_require__(649); -var isObj = __webpack_require__(590); - -/** - * Expose class utils - */ - -var cu = module.exports; - -/** - * Expose class utils: `cu` - */ - -cu.isObject = function isObject(val) { - return isObj(val) || typeof val === 'function'; -}; - -/** - * Returns true if an array has any of the given elements, or an - * object has any of the give keys. - * - * ```js - * cu.has(['a', 'b', 'c'], 'c'); - * //=> true - * - * cu.has(['a', 'b', 'c'], ['c', 'z']); - * //=> true - * - * cu.has({a: 'b', c: 'd'}, ['c', 'z']); - * //=> true - * ``` - * @param {Object} `obj` - * @param {String|Array} `val` - * @return {Boolean} - * @api public - */ - -cu.has = function has(obj, val) { - val = cu.arrayify(val); - var len = val.length; - - if (cu.isObject(obj)) { - for (var key in obj) { - if (val.indexOf(key) > -1) { - return true; - } - } - - var keys = cu.nativeKeys(obj); - return cu.has(keys, val); - } - - if (Array.isArray(obj)) { - var arr = obj; - while (len--) { - if (arr.indexOf(val[len]) > -1) { - return true; - } - } - return false; - } - - throw new TypeError('expected an array or object.'); -}; - -/** - * Returns true if an array or object has all of the given values. - * - * ```js - * cu.hasAll(['a', 'b', 'c'], 'c'); - * //=> true - * - * cu.hasAll(['a', 'b', 'c'], ['c', 'z']); - * //=> false - * - * cu.hasAll({a: 'b', c: 'd'}, ['c', 'z']); - * //=> false - * ``` - * @param {Object|Array} `val` - * @param {String|Array} `values` - * @return {Boolean} - * @api public - */ - -cu.hasAll = function hasAll(val, values) { - values = cu.arrayify(values); - var len = values.length; - while (len--) { - if (!cu.has(val, values[len])) { - return false; - } - } - return true; -}; - -/** - * Cast the given value to an array. - * - * ```js - * cu.arrayify('foo'); - * //=> ['foo'] - * - * cu.arrayify(['foo']); - * //=> ['foo'] - * ``` - * - * @param {String|Array} `val` - * @return {Array} - * @api public - */ - -cu.arrayify = function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -}; - -/** - * Noop - */ - -cu.noop = function noop() { - return; -}; - -/** - * Returns the first argument passed to the function. - */ - -cu.identity = function identity(val) { - return val; -}; - -/** - * Returns true if a value has a `contructor` - * - * ```js - * cu.hasConstructor({}); - * //=> true - * - * cu.hasConstructor(Object.create(null)); - * //=> false - * ``` - * @param {Object} `value` - * @return {Boolean} - * @api public - */ - -cu.hasConstructor = function hasConstructor(val) { - return cu.isObject(val) && typeof val.constructor !== 'undefined'; -}; - -/** - * Get the native `ownPropertyNames` from the constructor of the - * given `object`. An empty array is returned if the object does - * not have a constructor. - * - * ```js - * cu.nativeKeys({a: 'b', b: 'c', c: 'd'}) - * //=> ['a', 'b', 'c'] - * - * cu.nativeKeys(function(){}) - * //=> ['length', 'caller'] - * ``` - * - * @param {Object} `obj` Object that has a `constructor`. - * @return {Array} Array of keys. - * @api public - */ - -cu.nativeKeys = function nativeKeys(val) { - if (!cu.hasConstructor(val)) return []; - var keys = Object.getOwnPropertyNames(val); - if ('caller' in val) keys.push('caller'); - return keys; -}; - -/** - * Returns property descriptor `key` if it's an "own" property - * of the given object. - * - * ```js - * function App() {} - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this).length; - * } - * }); - * cu.getDescriptor(App.prototype, 'count'); - * // returns: - * // { - * // get: [Function], - * // set: undefined, - * // enumerable: false, - * // configurable: false - * // } - * ``` - * - * @param {Object} `obj` - * @param {String} `key` - * @return {Object} Returns descriptor `key` - * @api public - */ - -cu.getDescriptor = function getDescriptor(obj, key) { - if (!cu.isObject(obj)) { - throw new TypeError('expected an object.'); - } - if (typeof key !== 'string') { - throw new TypeError('expected key to be a string.'); - } - return Object.getOwnPropertyDescriptor(obj, key); -}; - -/** - * Copy a descriptor from one object to another. - * - * ```js - * function App() {} - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this).length; - * } - * }); - * var obj = {}; - * cu.copyDescriptor(obj, App.prototype, 'count'); - * ``` - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String} `name` - * @return {Object} - * @api public - */ - -cu.copyDescriptor = function copyDescriptor(receiver, provider, name) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - if (typeof name !== 'string') { - throw new TypeError('expected name to be a string.'); - } - - var val = cu.getDescriptor(provider, name); - if (val) Object.defineProperty(receiver, name, val); -}; - -/** - * Copy static properties, prototype properties, and descriptors - * from one object to another. - * - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public - */ - -cu.copy = function copy(receiver, provider, omit) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - var props = Object.getOwnPropertyNames(provider); - var keys = Object.keys(provider); - var len = props.length, - key; - omit = cu.arrayify(omit); - - while (len--) { - key = props[len]; - - if (cu.has(keys, key)) { - define(receiver, key, provider[key]); - } else if (!(key in receiver) && !cu.has(omit, key)) { - cu.copyDescriptor(receiver, provider, key); - } - } -}; - -/** - * Inherit the static properties, prototype properties, and descriptors - * from of an object. - * - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public - */ - -cu.inherit = function inherit(receiver, provider, omit) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - - var keys = []; - for (var key in provider) { - keys.push(key); - receiver[key] = provider[key]; - } - - keys = keys.concat(cu.arrayify(omit)); - - var a = provider.prototype || provider; - var b = receiver.prototype || receiver; - cu.copy(b, a, keys); -}; - -/** - * Returns a function for extending the static properties, - * prototype properties, and descriptors from the `Parent` - * constructor onto `Child` constructors. - * - * ```js - * var extend = cu.extend(Parent); - * Parent.extend(Child); - * - * // optional methods - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @param {Function} `Parent` Parent ctor - * @param {Function} `extend` Optional extend function to handle custom extensions. Useful when updating methods that require a specific prototype. - * @param {Function} `Child` Child ctor - * @param {Object} `proto` Optionally pass additional prototype properties to inherit. - * @return {Object} - * @api public - */ - -cu.extend = function() { - // keep it lazy, instead of assigning to `cu.extend` - return staticExtend.apply(null, arguments); -}; - -/** - * Bubble up events emitted from static methods on the Parent ctor. - * - * @param {Object} `Parent` - * @param {Array} `events` Event names to bubble up - * @api public - */ - -cu.bubble = function(Parent, events) { - events = events || []; - Parent.bubble = function(Child, arr) { - if (Array.isArray(arr)) { - events = union([], events, arr); - } - var len = events.length; - var idx = -1; - while (++idx < len) { - var name = events[idx]; - Parent.on(name, Child.emit.bind(Child, name)); - } - cu.bubble(Child, events); - }; -}; - - -/***/ }), -/* 645 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(646); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 646 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-descriptor - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); -var isAccessor = __webpack_require__(647); -var isData = __webpack_require__(648); - -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; - - -/***/ }), -/* 647 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; - -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (typeOf(obj) !== 'object') { - return false; - } - - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } - - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } - - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } - - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === accessor[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} - -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} - -/** - * Expose `isAccessorDescriptor` - */ - -module.exports = isAccessorDescriptor; - - -/***/ }), -/* 648 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-data-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var typeOf = __webpack_require__(592); - -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' -}; - -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; - } - - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (!('value' in obj) && !('writable' in obj)) { - return false; - } - - for (var key in obj) { - if (key === 'value') continue; - - if (!data.hasOwnProperty(key)) { - continue; - } - - if (typeOf(obj[key]) === data[key]) { - continue; - } - - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} - -/** - * Expose `isDataDescriptor` - */ - -module.exports = isDataDescriptor; - - -/***/ }), -/* 649 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * static-extend - * - * Copyright (c) 2016, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var copy = __webpack_require__(650); -var define = __webpack_require__(645); -var util = __webpack_require__(112); - -/** - * Returns a function for extending the static properties, - * prototype properties, and descriptors from the `Parent` - * constructor onto `Child` constructors. - * - * ```js - * var extend = require('static-extend'); - * Parent.extend = extend(Parent); - * - * // optionally pass a custom merge function as the second arg - * Parent.extend = extend(Parent, function(Child) { - * Child.prototype.mixin = function(key, val) { - * Child.prototype[key] = val; - * }; - * }); - * - * // extend "child" constructors - * Parent.extend(Child); - * - * // optionally define prototype methods as the second arg - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @param {Function} `Parent` Parent ctor - * @param {Function} `extendFn` Optional extend function for handling any necessary custom merging. Useful when updating methods that require a specific prototype. - * @param {Function} `Child` Child ctor - * @param {Object} `proto` Optionally pass additional prototype properties to inherit. - * @return {Object} - * @api public - */ - -function extend(Parent, extendFn) { - if (typeof Parent !== 'function') { - throw new TypeError('expected Parent to be a function.'); - } - - return function(Ctor, proto) { - if (typeof Ctor !== 'function') { - throw new TypeError('expected Ctor to be a function.'); - } - - util.inherits(Ctor, Parent); - copy(Ctor, Parent); - - // proto can be null or a plain object - if (typeof proto === 'object') { - var obj = Object.create(proto); - - for (var k in obj) { - Ctor.prototype[k] = obj[k]; - } - } - - // keep a reference to the parent prototype - define(Ctor.prototype, '_parent_', { - configurable: true, - set: function() {}, - get: function() { - return Parent.prototype; - } - }); - - if (typeof extendFn === 'function') { - extendFn(Ctor, Parent); - } - - Ctor.extend = extend(Ctor, extendFn); - }; -}; - -/** - * Expose `extend` - */ - -module.exports = extend; - - -/***/ }), -/* 650 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var typeOf = __webpack_require__(592); -var copyDescriptor = __webpack_require__(651); -var define = __webpack_require__(645); - -/** - * Copy static properties, prototype properties, and descriptors from one object to another. - * - * ```js - * function App() {} - * var proto = App.prototype; - * App.prototype.set = function() {}; - * App.prototype.get = function() {}; - * - * var obj = {}; - * copy(obj, proto); - * ``` - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public - */ - -function copy(receiver, provider, omit) { - if (!isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } - - var props = nativeKeys(provider); - var keys = Object.keys(provider); - var len = props.length; - omit = arrayify(omit); - - while (len--) { - var key = props[len]; - - if (has(keys, key)) { - define(receiver, key, provider[key]); - } else if (!(key in receiver) && !has(omit, key)) { - copyDescriptor(receiver, provider, key); - } - } -}; - -/** - * Return true if the given value is an object or function - */ - -function isObject(val) { - return typeOf(val) === 'object' || typeof val === 'function'; -} - -/** - * Returns true if an array has any of the given elements, or an - * object has any of the give keys. - * - * ```js - * has(['a', 'b', 'c'], 'c'); - * //=> true - * - * has(['a', 'b', 'c'], ['c', 'z']); - * //=> true - * - * has({a: 'b', c: 'd'}, ['c', 'z']); - * //=> true - * ``` - * @param {Object} `obj` - * @param {String|Array} `val` - * @return {Boolean} - */ - -function has(obj, val) { - val = arrayify(val); - var len = val.length; - - if (isObject(obj)) { - for (var key in obj) { - if (val.indexOf(key) > -1) { - return true; - } - } - - var keys = nativeKeys(obj); - return has(keys, val); - } - - if (Array.isArray(obj)) { - var arr = obj; - while (len--) { - if (arr.indexOf(val[len]) > -1) { - return true; - } - } - return false; - } - - throw new TypeError('expected an array or object.'); -} - -/** - * Cast the given value to an array. - * - * ```js - * arrayify('foo'); - * //=> ['foo'] - * - * arrayify(['foo']); - * //=> ['foo'] - * ``` - * - * @param {String|Array} `val` - * @return {Array} - */ - -function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -} - -/** - * Returns true if a value has a `contructor` - * - * ```js - * hasConstructor({}); - * //=> true - * - * hasConstructor(Object.create(null)); - * //=> false - * ``` - * @param {Object} `value` - * @return {Boolean} - */ - -function hasConstructor(val) { - return isObject(val) && typeof val.constructor !== 'undefined'; -} - -/** - * Get the native `ownPropertyNames` from the constructor of the - * given `object`. An empty array is returned if the object does - * not have a constructor. - * - * ```js - * nativeKeys({a: 'b', b: 'c', c: 'd'}) - * //=> ['a', 'b', 'c'] - * - * nativeKeys(function(){}) - * //=> ['length', 'caller'] - * ``` - * - * @param {Object} `obj` Object that has a `constructor`. - * @return {Array} Array of keys. - */ - -function nativeKeys(val) { - if (!hasConstructor(val)) return []; - return Object.getOwnPropertyNames(val); -} - -/** - * Expose `copy` - */ - -module.exports = copy; - -/** - * Expose `copy.has` for tests - */ - -module.exports.has = has; - - -/***/ }), -/* 651 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * copy-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -/** - * Copy a descriptor from one object to another. - * - * ```js - * function App() { - * this.cache = {}; - * } - * App.prototype.set = function(key, val) { - * this.cache[key] = val; - * return this; - * }; - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this.cache).length; - * } - * }); - * - * copy(App.prototype, 'count', 'len'); - * - * // create an instance - * var app = new App(); - * - * app.set('a', true); - * app.set('b', true); - * app.set('c', true); - * - * console.log(app.count); - * //=> 3 - * console.log(app.len); - * //=> 3 - * ``` - * @name copy - * @param {Object} `receiver` The target object - * @param {Object} `provider` The provider object - * @param {String} `from` The key to copy on provider. - * @param {String} `to` Optionally specify a new key name to use. - * @return {Object} - * @api public - */ - -module.exports = function copyDescriptor(receiver, provider, from, to) { - if (!isObject(provider) && typeof provider !== 'function') { - to = from; - from = provider; - provider = receiver; - } - if (!isObject(receiver) && typeof receiver !== 'function') { - throw new TypeError('expected the first argument to be an object'); - } - if (!isObject(provider) && typeof provider !== 'function') { - throw new TypeError('expected provider to be an object'); - } - - if (typeof to !== 'string') { - to = from; - } - if (typeof from !== 'string') { - throw new TypeError('expected key to be a string'); - } - - if (!(from in provider)) { - throw new Error('property "' + from + '" does not exist'); - } - - var val = Object.getOwnPropertyDescriptor(provider, from); - if (val) Object.defineProperty(receiver, to, val); -}; - -function isObject(val) { - return {}.toString.call(val) === '[object Object]'; -} - - - -/***/ }), -/* 652 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var use = __webpack_require__(653); -var define = __webpack_require__(645); -var debug = __webpack_require__(654)('snapdragon:compiler'); -var utils = __webpack_require__(660); - -/** - * Create a new `Compiler` with the given `options`. - * @param {Object} `options` - */ - -function Compiler(options, state) { - debug('initializing', __filename); - this.options = utils.extend({source: 'string'}, options); - this.state = state || {}; - this.compilers = {}; - this.output = ''; - this.set('eos', function(node) { - return this.emit(node.val, node); - }); - this.set('noop', function(node) { - return this.emit(node.val, node); - }); - this.set('bos', function(node) { - return this.emit(node.val, node); - }); - use(this); -} - -/** - * Prototype methods - */ - -Compiler.prototype = { - - /** - * Throw an error message with details including the cursor position. - * @param {String} `msg` Message to use in the Error. - */ - - error: function(msg, node) { - var pos = node.position || {start: {column: 0}}; - var message = this.options.source + ' column:' + pos.start.column + ': ' + msg; - - var err = new Error(message); - err.reason = msg; - err.column = pos.start.column; - err.source = this.pattern; - - if (this.options.silent) { - this.errors.push(err); - } else { - throw err; - } - }, - - /** - * Define a non-enumberable property on the `Compiler` instance. - * - * ```js - * compiler.define('foo', 'bar'); - * ``` - * @name .define - * @param {String} `key` propery name - * @param {any} `val` property value - * @return {Object} Returns the Compiler instance for chaining. - * @api public - */ - - define: function(key, val) { - define(this, key, val); - return this; - }, - - /** - * Emit `node.val` - */ - - emit: function(str, node) { - this.output += str; - return str; - }, - - /** - * Add a compiler `fn` with the given `name` - */ - - set: function(name, fn) { - this.compilers[name] = fn; - return this; - }, - - /** - * Get compiler `name`. - */ - - get: function(name) { - return this.compilers[name]; - }, - - /** - * Get the previous AST node. - */ - - prev: function(n) { - return this.ast.nodes[this.idx - (n || 1)] || { type: 'bos', val: '' }; - }, - - /** - * Get the next AST node. - */ - - next: function(n) { - return this.ast.nodes[this.idx + (n || 1)] || { type: 'eos', val: '' }; - }, - - /** - * Visit `node`. - */ - - visit: function(node, nodes, i) { - var fn = this.compilers[node.type]; - this.idx = i; - - if (typeof fn !== 'function') { - throw this.error('compiler "' + node.type + '" is not registered', node); - } - return fn.call(this, node, nodes, i); - }, - - /** - * Map visit over array of `nodes`. - */ - - mapVisit: function(nodes) { - if (!Array.isArray(nodes)) { - throw new TypeError('expected an array'); - } - var len = nodes.length; - var idx = -1; - while (++idx < len) { - this.visit(nodes[idx], nodes, idx); - } - return this; - }, - - /** - * Compile `ast`. - */ - - compile: function(ast, options) { - var opts = utils.extend({}, this.options, options); - this.ast = ast; - this.parsingErrors = this.ast.errors; - this.output = ''; - - // source map support - if (opts.sourcemap) { - var sourcemaps = __webpack_require__(680); - sourcemaps(this); - this.mapVisit(this.ast.nodes); - this.applySourceMaps(); - this.map = opts.sourcemap === 'generator' ? this.map : this.map.toJSON(); - return this; - } - - this.mapVisit(this.ast.nodes); - return this; - } -}; - -/** - * Expose `Compiler` - */ - -module.exports = Compiler; - - -/***/ }), -/* 653 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * use - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function base(app, options) { - if (!isObject(app) && typeof app !== 'function') { - throw new TypeError('expected an object or function'); - } - - var opts = isObject(options) ? options : {}; - var prop = typeof opts.prop === 'string' ? opts.prop : 'fns'; - if (!Array.isArray(app[prop])) { - define(app, prop, []); - } - - /** - * Define a plugin function to be passed to use. The only - * parameter exposed to the plugin is `app`, the object or function. - * passed to `use(app)`. `app` is also exposed as `this` in plugins. - * - * Additionally, **if a plugin returns a function, the function will - * be pushed onto the `fns` array**, allowing the plugin to be - * called at a later point by the `run` method. - * - * ```js - * var use = require('use'); - * - * // define a plugin - * function foo(app) { - * // do stuff - * } - * - * var app = function(){}; - * use(app); - * - * // register plugins - * app.use(foo); - * app.use(bar); - * app.use(baz); - * ``` - * @name .use - * @param {Function} `fn` plugin function to call - * @api public - */ - - define(app, 'use', use); - - /** - * Run all plugins on `fns`. Any plugin that returns a function - * when called by `use` is pushed onto the `fns` array. - * - * ```js - * var config = {}; - * app.run(config); - * ``` - * @name .run - * @param {Object} `value` Object to be modified by plugins. - * @return {Object} Returns the object passed to `run` - * @api public - */ - - define(app, 'run', function(val) { - if (!isObject(val)) return; - - if (!val.use || !val.run) { - define(val, prop, val[prop] || []); - define(val, 'use', use); - } - - if (!val[prop] || val[prop].indexOf(base) === -1) { - val.use(base); - } - - var self = this || app; - var fns = self[prop]; - var len = fns.length; - var idx = -1; - - while (++idx < len) { - val.use(fns[idx]); - } - return val; - }); - - /** - * Call plugin `fn`. If a function is returned push it into the - * `fns` array to be called by the `run` method. - */ - - function use(type, fn, options) { - var offset = 1; - - if (typeof type === 'string' || Array.isArray(type)) { - fn = wrap(type, fn); - offset++; - } else { - options = fn; - fn = type; - } - - if (typeof fn !== 'function') { - throw new TypeError('expected a function'); - } - - var self = this || app; - var fns = self[prop]; - - var args = [].slice.call(arguments, offset); - args.unshift(self); - - if (typeof opts.hook === 'function') { - opts.hook.apply(self, args); - } - - var val = fn.apply(self, args); - if (typeof val === 'function' && fns.indexOf(val) === -1) { - fns.push(val); - } - return self; - } - - /** - * Wrap a named plugin function so that it's only called on objects of the - * given `type` - * - * @param {String} `type` - * @param {Function} `fn` Plugin function - * @return {Function} - */ - - function wrap(type, fn) { - return function plugin() { - return this.type === type ? fn.apply(this, arguments) : plugin; - }; - } - - return app; -}; - -function isObject(val) { - return val && typeof val === 'object' && !Array.isArray(val); -} - -function define(obj, key, val) { - Object.defineProperty(obj, key, { - configurable: true, - writable: true, - value: val - }); -} - - -/***/ }), -/* 654 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. - */ - -if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(655); -} else { - module.exports = __webpack_require__(658); -} - - -/***/ }), -/* 655 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(656); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; - } - - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} - - -/***/ }), -/* 656 */ -/***/ (function(module, exports, __webpack_require__) { - - -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = __webpack_require__(657); - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; - -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ - -exports.formatters = {}; - -/** - * Previous log timestamp. - */ - -var prevTime; - -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ - -function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer - } - - return exports.colors[Math.abs(hash) % exports.colors.length]; -} - -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); - - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); - - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } - - return debug; -} - -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - -function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } -} - -/** - * Disable debug output. - * - * @api public - */ - -function disable() { - exports.enable(''); -} - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - - -/***/ }), -/* 657 */ -/***/ (function(module, exports) { - -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; -} - - -/***/ }), -/* 658 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Module dependencies. - */ - -var tty = __webpack_require__(122); -var util = __webpack_require__(112); - -/** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(656); -exports.init = init; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; - -/** - * Colors. - */ - -exports.colors = [6, 2, 3, 4, 5, 1]; - -/** - * Build up the default `inspectOpts` object from the environment variables. - * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js - */ - -exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); -}).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); - - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); - - obj[prop] = val; - return obj; -}, {}); - -/** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ - -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; - -if (1 !== fd && 2 !== fd) { - util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() -} - -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); - -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ - -function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); -} - -/** - * Map %o to `util.inspect()`, all on a single line. - */ - -exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); -}; - -/** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ - -exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts); -}; - -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ - -function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; - - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; - - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } -} - -/** - * Invokes `util.format()` with the specified arguments and writes to `stream`. - */ - -function log() { - return stream.write(util.format.apply(util, arguments) + '\n'); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - return process.env.DEBUG; -} - -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ - -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - case 'FILE': - var fs = __webpack_require__(134); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = __webpack_require__(659); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); - - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; - - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; -} - -/** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ - -function init (debug) { - debug.inspectOpts = {}; - - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } -} - -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - -exports.enable(load()); - - -/***/ }), -/* 659 */ -/***/ (function(module, exports) { - -module.exports = require("net"); - -/***/ }), -/* 660 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -exports.extend = __webpack_require__(661); -exports.SourceMap = __webpack_require__(662); -exports.sourceMapResolve = __webpack_require__(673); - -/** - * Convert backslash in the given string to forward slashes - */ - -exports.unixify = function(fp) { - return fp.split(/\\+/).join('/'); -}; - -/** - * Return true if `val` is a non-empty string - * - * @param {String} `str` - * @return {Boolean} - */ - -exports.isString = function(str) { - return str && typeof str === 'string'; -}; - -/** - * Cast `val` to an array - * @return {Array} - */ - -exports.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; - -/** - * Get the last `n` element from the given `array` - * @param {Array} `array` - * @return {*} - */ - -exports.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - - -/***/ }), -/* 661 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(602); - -module.exports = function extend(o/*, objects*/) { - if (!isObject(o)) { o = {}; } - - var len = arguments.length; - for (var i = 1; i < len; i++) { - var obj = arguments[i]; - - if (isObject(obj)) { - assign(o, obj); - } - } - return o; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - - -/***/ }), -/* 662 */ -/***/ (function(module, exports, __webpack_require__) { - -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ -exports.SourceMapGenerator = __webpack_require__(663).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(669).SourceMapConsumer; -exports.SourceNode = __webpack_require__(672).SourceNode; - - -/***/ }), -/* 663 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var base64VLQ = __webpack_require__(664); -var util = __webpack_require__(666); -var ArraySet = __webpack_require__(667).ArraySet; -var MappingList = __webpack_require__(668).MappingList; - -/** - * An instance of the SourceMapGenerator represents a source map which is - * being built incrementally. You may pass an object with the following - * properties: - * - * - file: The filename of the generated source. - * - sourceRoot: A root for all relative URLs in this source map. - */ -function SourceMapGenerator(aArgs) { - if (!aArgs) { - aArgs = {}; - } - this._file = util.getArg(aArgs, 'file', null); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._skipValidation = util.getArg(aArgs, 'skipValidation', false); - this._sources = new ArraySet(); - this._names = new ArraySet(); - this._mappings = new MappingList(); - this._sourcesContents = null; -} - -SourceMapGenerator.prototype._version = 3; - -/** - * Creates a new SourceMapGenerator based on a SourceMapConsumer - * - * @param aSourceMapConsumer The SourceMap. - */ -SourceMapGenerator.fromSourceMap = - function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; - - if (mapping.source != null) { - newMapping.source = mapping.source; - if (sourceRoot != null) { - newMapping.source = util.relative(sourceRoot, newMapping.source); - } - - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; - - if (mapping.name != null) { - newMapping.name = mapping.name; - } - } - - generator.addMapping(newMapping); - }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - generator.setSourceContent(sourceFile, content); - } - }); - return generator; - }; - -/** - * Add a single mapping from original source line and column to the generated - * source's line and column for this source map being created. The mapping - * object should have the following properties: - * - * - generated: An object with the generated line and column positions. - * - original: An object with the original line and column positions. - * - source: The original source file (relative to the sourceRoot). - * - name: An optional original token name for this mapping. - */ -SourceMapGenerator.prototype.addMapping = - function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); - - if (!this._skipValidation) { - this._validateMapping(generated, original, source, name); - } - - if (source != null) { - source = String(source); - if (!this._sources.has(source)) { - this._sources.add(source); - } - } - - if (name != null) { - name = String(name); - if (!this._names.has(name)) { - this._names.add(name); - } - } - - this._mappings.add({ - generatedLine: generated.line, - generatedColumn: generated.column, - originalLine: original != null && original.line, - originalColumn: original != null && original.column, - source: source, - name: name - }); - }; - -/** - * Set the source content for a source file. - */ -SourceMapGenerator.prototype.setSourceContent = - function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot != null) { - source = util.relative(this._sourceRoot, source); - } - - if (aSourceContent != null) { - // Add the source content to the _sourcesContents map. - // Create a new _sourcesContents map if the property is null. - if (!this._sourcesContents) { - this._sourcesContents = Object.create(null); - } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else if (this._sourcesContents) { - // Remove the source file from the _sourcesContents map. - // If the _sourcesContents map is empty, set the property to null. - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; - } - } - }; - -/** - * Applies the mappings of a sub-source-map for a specific source file to the - * source map being generated. Each mapping to the supplied source file is - * rewritten using the supplied source map. Note: The resolution for the - * resulting mappings is the minimium of this map and the supplied map. - * - * @param aSourceMapConsumer The source map to be applied. - * @param aSourceFile Optional. The filename of the source file. - * If omitted, SourceMapConsumer's file property will be used. - * @param aSourceMapPath Optional. The dirname of the path to the source map - * to be applied. If relative, it is relative to the SourceMapConsumer. - * This parameter is needed when the two source maps aren't in the same - * directory, and the source map to be applied contains relative source - * paths. If so, those relative source paths need to be rewritten - * relative to the SourceMapGenerator. - */ -SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { - var sourceFile = aSourceFile; - // If aSourceFile is omitted, we will use the file property of the SourceMap - if (aSourceFile == null) { - if (aSourceMapConsumer.file == null) { - throw new Error( - 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + - 'or the source map\'s "file" property. Both were omitted.' - ); - } - sourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - // Make "sourceFile" relative if an absolute Url is passed. - if (sourceRoot != null) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - // Applying the SourceMap can add and remove items from the sources and - // the names array. - var newSources = new ArraySet(); - var newNames = new ArraySet(); - - // Find mappings for the "sourceFile" - this._mappings.unsortedForEach(function (mapping) { - if (mapping.source === sourceFile && mapping.originalLine != null) { - // Check if it can be mapped by the source map, then update the mapping. - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.originalLine, - column: mapping.originalColumn - }); - if (original.source != null) { - // Copy mapping - mapping.source = original.source; - if (aSourceMapPath != null) { - mapping.source = util.join(aSourceMapPath, mapping.source) - } - if (sourceRoot != null) { - mapping.source = util.relative(sourceRoot, mapping.source); - } - mapping.originalLine = original.line; - mapping.originalColumn = original.column; - if (original.name != null) { - mapping.name = original.name; - } - } - } - - var source = mapping.source; - if (source != null && !newSources.has(source)) { - newSources.add(source); - } - - var name = mapping.name; - if (name != null && !newNames.has(name)) { - newNames.add(name); - } - - }, this); - this._sources = newSources; - this._names = newNames; - - // Copy sourcesContents of applied map. - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - if (aSourceMapPath != null) { - sourceFile = util.join(aSourceMapPath, sourceFile); - } - if (sourceRoot != null) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - this.setSourceContent(sourceFile, content); - } - }, this); - }; - -/** - * A mapping can have one of the three levels of data: - * - * 1. Just the generated position. - * 2. The Generated position, original position, and original source. - * 3. Generated and original position, original source, as well as a name - * token. - * - * To maintain consistency, we validate that any new mapping being added falls - * in to one of these categories. - */ -SourceMapGenerator.prototype._validateMapping = - function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, - aName) { - // When aOriginal is truthy but has empty values for .line and .column, - // it is most likely a programmer error. In this case we throw a very - // specific error message to try to guide them the right way. - // For example: https://github.com/Polymer/polymer-bundler/pull/519 - if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') { - throw new Error( - 'original.line and original.column are not numbers -- you probably meant to omit ' + - 'the original mapping entirely and only map the generated position. If so, pass ' + - 'null for the original mapping instead of an object with empty or null values.' - ); - } - - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aGenerated.line > 0 && aGenerated.column >= 0 - && !aOriginal && !aSource && !aName) { - // Case 1. - return; - } - else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aOriginal && 'line' in aOriginal && 'column' in aOriginal - && aGenerated.line > 0 && aGenerated.column >= 0 - && aOriginal.line > 0 && aOriginal.column >= 0 - && aSource) { - // Cases 2 and 3. - return; - } - else { - throw new Error('Invalid mapping: ' + JSON.stringify({ - generated: aGenerated, - source: aSource, - original: aOriginal, - name: aName - })); - } - }; - -/** - * Serialize the accumulated mappings in to the stream of base 64 VLQs - * specified by the source map format. - */ -SourceMapGenerator.prototype._serializeMappings = - function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var next; - var mapping; - var nameIdx; - var sourceIdx; - - var mappings = this._mappings.toArray(); - for (var i = 0, len = mappings.length; i < len; i++) { - mapping = mappings[i]; - next = '' - - if (mapping.generatedLine !== previousGeneratedLine) { - previousGeneratedColumn = 0; - while (mapping.generatedLine !== previousGeneratedLine) { - next += ';'; - previousGeneratedLine++; - } - } - else { - if (i > 0) { - if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { - continue; - } - next += ','; - } - } - - next += base64VLQ.encode(mapping.generatedColumn - - previousGeneratedColumn); - previousGeneratedColumn = mapping.generatedColumn; - - if (mapping.source != null) { - sourceIdx = this._sources.indexOf(mapping.source); - next += base64VLQ.encode(sourceIdx - previousSource); - previousSource = sourceIdx; - - // lines are stored 0-based in SourceMap spec version 3 - next += base64VLQ.encode(mapping.originalLine - 1 - - previousOriginalLine); - previousOriginalLine = mapping.originalLine - 1; - - next += base64VLQ.encode(mapping.originalColumn - - previousOriginalColumn); - previousOriginalColumn = mapping.originalColumn; - - if (mapping.name != null) { - nameIdx = this._names.indexOf(mapping.name); - next += base64VLQ.encode(nameIdx - previousName); - previousName = nameIdx; - } - } - - result += next; - } - - return result; - }; - -SourceMapGenerator.prototype._generateSourcesContent = - function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { - return aSources.map(function (source) { - if (!this._sourcesContents) { - return null; - } - if (aSourceRoot != null) { - source = util.relative(aSourceRoot, source); - } - var key = util.toSetString(source); - return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) - ? this._sourcesContents[key] - : null; - }, this); - }; - -/** - * Externalize the source map. - */ -SourceMapGenerator.prototype.toJSON = - function SourceMapGenerator_toJSON() { - var map = { - version: this._version, - sources: this._sources.toArray(), - names: this._names.toArray(), - mappings: this._serializeMappings() - }; - if (this._file != null) { - map.file = this._file; - } - if (this._sourceRoot != null) { - map.sourceRoot = this._sourceRoot; - } - if (this._sourcesContents) { - map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); - } - - return map; - }; - -/** - * Render the source map being generated to a string. - */ -SourceMapGenerator.prototype.toString = - function SourceMapGenerator_toString() { - return JSON.stringify(this.toJSON()); - }; - -exports.SourceMapGenerator = SourceMapGenerator; - - -/***/ }), -/* 664 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - * - * Based on the Base 64 VLQ implementation in Closure Compiler: - * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java - * - * Copyright 2011 The Closure Compiler Authors. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -var base64 = __webpack_require__(665); - -// A single base 64 digit can contain 6 bits of data. For the base 64 variable -// length quantities we use in the source map spec, the first bit is the sign, -// the next four bits are the actual value, and the 6th bit is the -// continuation bit. The continuation bit tells us whether there are more -// digits in this value following this digit. -// -// Continuation -// | Sign -// | | -// V V -// 101011 - -var VLQ_BASE_SHIFT = 5; - -// binary: 100000 -var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - -// binary: 011111 -var VLQ_BASE_MASK = VLQ_BASE - 1; - -// binary: 100000 -var VLQ_CONTINUATION_BIT = VLQ_BASE; - -/** - * Converts from a two-complement value to a value where the sign bit is - * placed in the least significant bit. For example, as decimals: - * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) - * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) - */ -function toVLQSigned(aValue) { - return aValue < 0 - ? ((-aValue) << 1) + 1 - : (aValue << 1) + 0; -} - -/** - * Converts to a two-complement value from a value where the sign bit is - * placed in the least significant bit. For example, as decimals: - * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 - * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 - */ -function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; - return isNegative - ? -shifted - : shifted; -} - -/** - * Returns the base 64 VLQ encoded value. - */ -exports.encode = function base64VLQ_encode(aValue) { - var encoded = ""; - var digit; - - var vlq = toVLQSigned(aValue); - - do { - digit = vlq & VLQ_BASE_MASK; - vlq >>>= VLQ_BASE_SHIFT; - if (vlq > 0) { - // There are still more digits in this value, so we must make sure the - // continuation bit is marked. - digit |= VLQ_CONTINUATION_BIT; - } - encoded += base64.encode(digit); - } while (vlq > 0); - - return encoded; -}; - -/** - * Decodes the next base 64 VLQ value from the given string and returns the - * value and the rest of the string via the out parameter. - */ -exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; - - do { - if (aIndex >= strLen) { - throw new Error("Expected more digits in base 64 VLQ value."); - } - - digit = base64.decode(aStr.charCodeAt(aIndex++)); - if (digit === -1) { - throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1)); - } - - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - - aOutParam.value = fromVLQSigned(result); - aOutParam.rest = aIndex; -}; - - -/***/ }), -/* 665 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); - -/** - * Encode an integer in the range of 0 to 63 to a single base 64 digit. - */ -exports.encode = function (number) { - if (0 <= number && number < intToCharMap.length) { - return intToCharMap[number]; - } - throw new TypeError("Must be between 0 and 63: " + number); -}; - -/** - * Decode a single base 64 character code digit to an integer. Returns -1 on - * failure. - */ -exports.decode = function (charCode) { - var bigA = 65; // 'A' - var bigZ = 90; // 'Z' - - var littleA = 97; // 'a' - var littleZ = 122; // 'z' - - var zero = 48; // '0' - var nine = 57; // '9' - - var plus = 43; // '+' - var slash = 47; // '/' - - var littleOffset = 26; - var numberOffset = 52; - - // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ - if (bigA <= charCode && charCode <= bigZ) { - return (charCode - bigA); - } - - // 26 - 51: abcdefghijklmnopqrstuvwxyz - if (littleA <= charCode && charCode <= littleZ) { - return (charCode - littleA + littleOffset); - } - - // 52 - 61: 0123456789 - if (zero <= charCode && charCode <= nine) { - return (charCode - zero + numberOffset); - } - - // 62: + - if (charCode == plus) { - return 62; - } - - // 63: / - if (charCode == slash) { - return 63; - } - - // Invalid base64 digit. - return -1; -}; - - -/***/ }), -/* 666 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -/** - * This is a helper function for getting values from parameter/options - * objects. - * - * @param args The object we are extracting values from - * @param name The name of the property we are getting. - * @param defaultValue An optional value to return if the property is missing - * from the object. If this is not specified and the property is missing, an - * error will be thrown. - */ -function getArg(aArgs, aName, aDefaultValue) { - if (aName in aArgs) { - return aArgs[aName]; - } else if (arguments.length === 3) { - return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); - } -} -exports.getArg = getArg; - -var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/; -var dataUrlRegexp = /^data:.+\,.+$/; - -function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; - } - return { - scheme: match[1], - auth: match[2], - host: match[3], - port: match[4], - path: match[5] - }; -} -exports.urlParse = urlParse; - -function urlGenerate(aParsedUrl) { - var url = ''; - if (aParsedUrl.scheme) { - url += aParsedUrl.scheme + ':'; - } - url += '//'; - if (aParsedUrl.auth) { - url += aParsedUrl.auth + '@'; - } - if (aParsedUrl.host) { - url += aParsedUrl.host; - } - if (aParsedUrl.port) { - url += ":" + aParsedUrl.port - } - if (aParsedUrl.path) { - url += aParsedUrl.path; - } - return url; -} -exports.urlGenerate = urlGenerate; - -/** - * Normalizes a path, or the path portion of a URL: - * - * - Replaces consecutive slashes with one slash. - * - Removes unnecessary '.' parts. - * - Removes unnecessary '/..' parts. - * - * Based on code in the Node.js 'path' core module. - * - * @param aPath The path or url to normalize. - */ -function normalize(aPath) { - var path = aPath; - var url = urlParse(aPath); - if (url) { - if (!url.path) { - return aPath; - } - path = url.path; - } - var isAbsolute = exports.isAbsolute(path); - - var parts = path.split(/\/+/); - for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { - part = parts[i]; - if (part === '.') { - parts.splice(i, 1); - } else if (part === '..') { - up++; - } else if (up > 0) { - if (part === '') { - // The first part is blank if the path is absolute. Trying to go - // above the root is a no-op. Therefore we can remove all '..' parts - // directly after the root. - parts.splice(i + 1, up); - up = 0; - } else { - parts.splice(i, 2); - up--; - } - } - } - path = parts.join('/'); - - if (path === '') { - path = isAbsolute ? '/' : '.'; - } - - if (url) { - url.path = path; - return urlGenerate(url); - } - return path; -} -exports.normalize = normalize; - -/** - * Joins two paths/URLs. - * - * @param aRoot The root path or URL. - * @param aPath The path or URL to be joined with the root. - * - * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a - * scheme-relative URL: Then the scheme of aRoot, if any, is prepended - * first. - * - Otherwise aPath is a path. If aRoot is a URL, then its path portion - * is updated with the result and aRoot is returned. Otherwise the result - * is returned. - * - If aPath is absolute, the result is aPath. - * - Otherwise the two paths are joined with a slash. - * - Joining for example 'http://' and 'www.example.com' is also supported. - */ -function join(aRoot, aPath) { - if (aRoot === "") { - aRoot = "."; - } - if (aPath === "") { - aPath = "."; - } - var aPathUrl = urlParse(aPath); - var aRootUrl = urlParse(aRoot); - if (aRootUrl) { - aRoot = aRootUrl.path || '/'; - } - - // `join(foo, '//www.example.org')` - if (aPathUrl && !aPathUrl.scheme) { - if (aRootUrl) { - aPathUrl.scheme = aRootUrl.scheme; - } - return urlGenerate(aPathUrl); - } - - if (aPathUrl || aPath.match(dataUrlRegexp)) { - return aPath; - } - - // `join('http://', 'www.example.com')` - if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { - aRootUrl.host = aPath; - return urlGenerate(aRootUrl); - } - - var joined = aPath.charAt(0) === '/' - ? aPath - : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); - - if (aRootUrl) { - aRootUrl.path = joined; - return urlGenerate(aRootUrl); - } - return joined; -} -exports.join = join; - -exports.isAbsolute = function (aPath) { - return aPath.charAt(0) === '/' || !!aPath.match(urlRegexp); -}; - -/** - * Make a path relative to a URL or another path. - * - * @param aRoot The root path or URL. - * @param aPath The path or URL to be made relative to aRoot. - */ -function relative(aRoot, aPath) { - if (aRoot === "") { - aRoot = "."; - } - - aRoot = aRoot.replace(/\/$/, ''); - - // It is possible for the path to be above the root. In this case, simply - // checking whether the root is a prefix of the path won't work. Instead, we - // need to remove components from the root one by one, until either we find - // a prefix that fits, or we run out of components to remove. - var level = 0; - while (aPath.indexOf(aRoot + '/') !== 0) { - var index = aRoot.lastIndexOf("/"); - if (index < 0) { - return aPath; - } - - // If the only part of the root that is left is the scheme (i.e. http://, - // file:///, etc.), one or more slashes (/), or simply nothing at all, we - // have exhausted all components, so the path is not relative to the root. - aRoot = aRoot.slice(0, index); - if (aRoot.match(/^([^\/]+:\/)?\/*$/)) { - return aPath; - } - - ++level; - } - - // Make sure we add a "../" for each component we removed from the root. - return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1); -} -exports.relative = relative; - -var supportsNullProto = (function () { - var obj = Object.create(null); - return !('__proto__' in obj); -}()); - -function identity (s) { - return s; -} - -/** - * Because behavior goes wacky when you set `__proto__` on objects, we - * have to prefix all the strings in our set with an arbitrary character. - * - * See https://github.com/mozilla/source-map/pull/31 and - * https://github.com/mozilla/source-map/issues/30 - * - * @param String aStr - */ -function toSetString(aStr) { - if (isProtoString(aStr)) { - return '$' + aStr; - } - - return aStr; -} -exports.toSetString = supportsNullProto ? identity : toSetString; - -function fromSetString(aStr) { - if (isProtoString(aStr)) { - return aStr.slice(1); - } - - return aStr; -} -exports.fromSetString = supportsNullProto ? identity : fromSetString; - -function isProtoString(s) { - if (!s) { - return false; - } - - var length = s.length; - - if (length < 9 /* "__proto__".length */) { - return false; - } - - if (s.charCodeAt(length - 1) !== 95 /* '_' */ || - s.charCodeAt(length - 2) !== 95 /* '_' */ || - s.charCodeAt(length - 3) !== 111 /* 'o' */ || - s.charCodeAt(length - 4) !== 116 /* 't' */ || - s.charCodeAt(length - 5) !== 111 /* 'o' */ || - s.charCodeAt(length - 6) !== 114 /* 'r' */ || - s.charCodeAt(length - 7) !== 112 /* 'p' */ || - s.charCodeAt(length - 8) !== 95 /* '_' */ || - s.charCodeAt(length - 9) !== 95 /* '_' */) { - return false; - } - - for (var i = length - 10; i >= 0; i--) { - if (s.charCodeAt(i) !== 36 /* '$' */) { - return false; - } - } - - return true; -} - -/** - * Comparator between two mappings where the original positions are compared. - * - * Optionally pass in `true` as `onlyCompareGenerated` to consider two - * mappings with the same original source/line/column, but different generated - * line and column the same. Useful when searching for a mapping with a - * stubbed out mapping. - */ -function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { - var cmp = mappingA.source - mappingB.source; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0 || onlyCompareOriginal) { - return cmp; - } - - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } - - return mappingA.name - mappingB.name; -} -exports.compareByOriginalPositions = compareByOriginalPositions; - -/** - * Comparator between two mappings with deflated source and name indices where - * the generated positions are compared. - * - * Optionally pass in `true` as `onlyCompareGenerated` to consider two - * mappings with the same generated line and column, but different - * source/name/original line and column the same. Useful when searching for a - * mapping with a stubbed out mapping. - */ -function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0 || onlyCompareGenerated) { - return cmp; - } - - cmp = mappingA.source - mappingB.source; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0) { - return cmp; - } - - return mappingA.name - mappingB.name; -} -exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated; - -function strcmp(aStr1, aStr2) { - if (aStr1 === aStr2) { - return 0; - } - - if (aStr1 > aStr2) { - return 1; - } - - return -1; -} - -/** - * Comparator between two mappings with inflated source and name strings where - * the generated positions are compared. - */ -function compareByGeneratedPositionsInflated(mappingA, mappingB) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0) { - return cmp; - } - - cmp = strcmp(mappingA.source, mappingB.source); - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } - - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0) { - return cmp; - } - - return strcmp(mappingA.name, mappingB.name); -} -exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated; - - -/***/ }), -/* 667 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var util = __webpack_require__(666); -var has = Object.prototype.hasOwnProperty; -var hasNativeMap = typeof Map !== "undefined"; - -/** - * A data structure which is a combination of an array and a set. Adding a new - * member is O(1), testing for membership is O(1), and finding the index of an - * element is O(1). Removing elements from the set is not supported. Only - * strings are supported for membership. - */ -function ArraySet() { - this._array = []; - this._set = hasNativeMap ? new Map() : Object.create(null); -} - -/** - * Static method for creating ArraySet instances from an existing array. - */ -ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { - var set = new ArraySet(); - for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i], aAllowDuplicates); - } - return set; -}; - -/** - * Return how many unique items are in this ArraySet. If duplicates have been - * added, than those do not count towards the size. - * - * @returns Number - */ -ArraySet.prototype.size = function ArraySet_size() { - return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length; -}; - -/** - * Add the given string to this set. - * - * @param String aStr - */ -ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var sStr = hasNativeMap ? aStr : util.toSetString(aStr); - var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); - } - if (!isDuplicate) { - if (hasNativeMap) { - this._set.set(aStr, idx); - } else { - this._set[sStr] = idx; - } - } -}; - -/** - * Is the given string a member of this set? - * - * @param String aStr - */ -ArraySet.prototype.has = function ArraySet_has(aStr) { - if (hasNativeMap) { - return this._set.has(aStr); - } else { - var sStr = util.toSetString(aStr); - return has.call(this._set, sStr); - } -}; - -/** - * What is the index of the given string in the array? - * - * @param String aStr - */ -ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (hasNativeMap) { - var idx = this._set.get(aStr); - if (idx >= 0) { - return idx; - } - } else { - var sStr = util.toSetString(aStr); - if (has.call(this._set, sStr)) { - return this._set[sStr]; - } - } - - throw new Error('"' + aStr + '" is not in the set.'); -}; - -/** - * What is the element at the given index? - * - * @param Number aIdx - */ -ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; - } - throw new Error('No element indexed by ' + aIdx); -}; - -/** - * Returns the array representation of this set (which has the proper indices - * indicated by indexOf). Note that this is a copy of the internal array used - * for storing the members so that no one can mess with internal state. - */ -ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); -}; - -exports.ArraySet = ArraySet; - - -/***/ }), -/* 668 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2014 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var util = __webpack_require__(666); - -/** - * Determine whether mappingB is after mappingA with respect to generated - * position. - */ -function generatedPositionAfter(mappingA, mappingB) { - // Optimized for most common case - var lineA = mappingA.generatedLine; - var lineB = mappingB.generatedLine; - var columnA = mappingA.generatedColumn; - var columnB = mappingB.generatedColumn; - return lineB > lineA || lineB == lineA && columnB >= columnA || - util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0; -} - -/** - * A data structure to provide a sorted view of accumulated mappings in a - * performance conscious manner. It trades a neglibable overhead in general - * case for a large speedup in case of mappings being added in order. - */ -function MappingList() { - this._array = []; - this._sorted = true; - // Serves as infimum - this._last = {generatedLine: -1, generatedColumn: 0}; -} - -/** - * Iterate through internal items. This method takes the same arguments that - * `Array.prototype.forEach` takes. - * - * NOTE: The order of the mappings is NOT guaranteed. - */ -MappingList.prototype.unsortedForEach = - function MappingList_forEach(aCallback, aThisArg) { - this._array.forEach(aCallback, aThisArg); - }; - -/** - * Add the given source mapping. - * - * @param Object aMapping - */ -MappingList.prototype.add = function MappingList_add(aMapping) { - if (generatedPositionAfter(this._last, aMapping)) { - this._last = aMapping; - this._array.push(aMapping); - } else { - this._sorted = false; - this._array.push(aMapping); - } -}; - -/** - * Returns the flat, sorted array of mappings. The mappings are sorted by - * generated position. - * - * WARNING: This method returns internal data without copying, for - * performance. The return value must NOT be mutated, and should be treated as - * an immutable borrow. If you want to take ownership, you must make your own - * copy. - */ -MappingList.prototype.toArray = function MappingList_toArray() { - if (!this._sorted) { - this._array.sort(util.compareByGeneratedPositionsInflated); - this._sorted = true; - } - return this._array; -}; - -exports.MappingList = MappingList; - - -/***/ }), -/* 669 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var util = __webpack_require__(666); -var binarySearch = __webpack_require__(670); -var ArraySet = __webpack_require__(667).ArraySet; -var base64VLQ = __webpack_require__(664); -var quickSort = __webpack_require__(671).quickSort; - -function SourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - return sourceMap.sections != null - ? new IndexedSourceMapConsumer(sourceMap) - : new BasicSourceMapConsumer(sourceMap); -} - -SourceMapConsumer.fromSourceMap = function(aSourceMap) { - return BasicSourceMapConsumer.fromSourceMap(aSourceMap); -} - -/** - * The version of the source mapping spec that we are consuming. - */ -SourceMapConsumer.prototype._version = 3; - -// `__generatedMappings` and `__originalMappings` are arrays that hold the -// parsed mapping coordinates from the source map's "mappings" attribute. They -// are lazily instantiated, accessed via the `_generatedMappings` and -// `_originalMappings` getters respectively, and we only parse the mappings -// and create these arrays once queried for a source location. We jump through -// these hoops because there can be many thousands of mappings, and parsing -// them is expensive, so we only want to do it if we must. -// -// Each object in the arrays is of the form: -// -// { -// generatedLine: The line number in the generated code, -// generatedColumn: The column number in the generated code, -// source: The path to the original source file that generated this -// chunk of code, -// originalLine: The line number in the original source that -// corresponds to this chunk of generated code, -// originalColumn: The column number in the original source that -// corresponds to this chunk of generated code, -// name: The name of the original symbol which generated this chunk of -// code. -// } -// -// All properties except for `generatedLine` and `generatedColumn` can be -// `null`. -// -// `_generatedMappings` is ordered by the generated positions. -// -// `_originalMappings` is ordered by the original positions. - -SourceMapConsumer.prototype.__generatedMappings = null; -Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { - get: function () { - if (!this.__generatedMappings) { - this._parseMappings(this._mappings, this.sourceRoot); - } - - return this.__generatedMappings; - } -}); - -SourceMapConsumer.prototype.__originalMappings = null; -Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { - get: function () { - if (!this.__originalMappings) { - this._parseMappings(this._mappings, this.sourceRoot); - } - - return this.__originalMappings; - } -}); - -SourceMapConsumer.prototype._charIsMappingSeparator = - function SourceMapConsumer_charIsMappingSeparator(aStr, index) { - var c = aStr.charAt(index); - return c === ";" || c === ","; - }; - -/** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). - */ -SourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - throw new Error("Subclasses must implement _parseMappings"); - }; - -SourceMapConsumer.GENERATED_ORDER = 1; -SourceMapConsumer.ORIGINAL_ORDER = 2; - -SourceMapConsumer.GREATEST_LOWER_BOUND = 1; -SourceMapConsumer.LEAST_UPPER_BOUND = 2; - -/** - * Iterate over each mapping between an original source/line/column and a - * generated line/column in this source map. - * - * @param Function aCallback - * The function that is called with each mapping. - * @param Object aContext - * Optional. If specified, this object will be the value of `this` every - * time that `aCallback` is called. - * @param aOrder - * Either `SourceMapConsumer.GENERATED_ORDER` or - * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to - * iterate over the mappings sorted by the generated file's line/column - * order or the original's source/line/column order, respectively. Defaults to - * `SourceMapConsumer.GENERATED_ORDER`. - */ -SourceMapConsumer.prototype.eachMapping = - function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - - var mappings; - switch (order) { - case SourceMapConsumer.GENERATED_ORDER: - mappings = this._generatedMappings; - break; - case SourceMapConsumer.ORIGINAL_ORDER: - mappings = this._originalMappings; - break; - default: - throw new Error("Unknown order of iteration."); - } - - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source === null ? null : this._sources.at(mapping.source); - if (source != null && sourceRoot != null) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name === null ? null : this._names.at(mapping.name) - }; - }, this).forEach(aCallback, context); - }; - -/** - * Returns all generated line and column information for the original source, - * line, and column provided. If no column is provided, returns all mappings - * corresponding to a either the line we are searching for or the next - * closest line that has any mappings. Otherwise, returns all mappings - * corresponding to the given line and either the column we are searching for - * or the next closest column that has any offsets. - * - * The only argument is an object with the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: Optional. the column number in the original source. - * - * and an array of objects is returned, each with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ -SourceMapConsumer.prototype.allGeneratedPositionsFor = - function SourceMapConsumer_allGeneratedPositionsFor(aArgs) { - var line = util.getArg(aArgs, 'line'); - - // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping - // returns the index of the closest mapping less than the needle. By - // setting needle.originalColumn to 0, we thus find the last mapping for - // the given line, provided such a mapping exists. - var needle = { - source: util.getArg(aArgs, 'source'), - originalLine: line, - originalColumn: util.getArg(aArgs, 'column', 0) - }; - - if (this.sourceRoot != null) { - needle.source = util.relative(this.sourceRoot, needle.source); - } - if (!this._sources.has(needle.source)) { - return []; - } - needle.source = this._sources.indexOf(needle.source); - - var mappings = []; - - var index = this._findMapping(needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - binarySearch.LEAST_UPPER_BOUND); - if (index >= 0) { - var mapping = this._originalMappings[index]; - - if (aArgs.column === undefined) { - var originalLine = mapping.originalLine; - - // Iterate until either we run out of mappings, or we run into - // a mapping for a different line than the one we found. Since - // mappings are sorted, this is guaranteed to find all mappings for - // the line we found. - while (mapping && mapping.originalLine === originalLine) { - mappings.push({ - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }); - - mapping = this._originalMappings[++index]; - } - } else { - var originalColumn = mapping.originalColumn; - - // Iterate until either we run out of mappings, or we run into - // a mapping for a different line than the one we were searching for. - // Since mappings are sorted, this is guaranteed to find all mappings for - // the line we are searching for. - while (mapping && - mapping.originalLine === line && - mapping.originalColumn == originalColumn) { - mappings.push({ - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }); - - mapping = this._originalMappings[++index]; - } - } - } - - return mappings; - }; - -exports.SourceMapConsumer = SourceMapConsumer; - -/** - * A BasicSourceMapConsumer instance represents a parsed source map which we can - * query for information about the original file positions by giving it a file - * position in the generated source. - * - * The only parameter is the raw source map (either as a JSON string, or - * already parsed to an object). According to the spec, source maps have the - * following attributes: - * - * - version: Which version of the source map spec this map is following. - * - sources: An array of URLs to the original source files. - * - names: An array of identifiers which can be referrenced by individual mappings. - * - sourceRoot: Optional. The URL root from which all sources are relative. - * - sourcesContent: Optional. An array of contents of the original source files. - * - mappings: A string of base64 VLQs which contain the actual mappings. - * - file: Optional. The generated file this source map is associated with. - * - * Here is an example source map, taken from the source map spec[0]: - * - * { - * version : 3, - * file: "out.js", - * sourceRoot : "", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AA,AB;;ABCDE;" - * } - * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# - */ -function BasicSourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - var version = util.getArg(sourceMap, 'version'); - var sources = util.getArg(sourceMap, 'sources'); - // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which - // requires the array) to play nice here. - var names = util.getArg(sourceMap, 'names', []); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file', null); - - // Once again, Sass deviates from the spec and supplies the version as a - // string rather than a number, so we use loose equality checking here. - if (version != this._version) { - throw new Error('Unsupported version: ' + version); - } - - sources = sources - .map(String) - // Some source maps produce relative source paths like "./foo.js" instead of - // "foo.js". Normalize these first so that future comparisons will succeed. - // See bugzil.la/1090768. - .map(util.normalize) - // Always ensure that absolute sources are internally stored relative to - // the source root, if the source root is absolute. Not doing this would - // be particularly problematic when the source root is a prefix of the - // source (valid, but why??). See github issue #199 and bugzil.la/1188982. - .map(function (source) { - return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source) - ? util.relative(sourceRoot, source) - : source; - }); - - // Pass `true` below to allow duplicate names and sources. While source maps - // are intended to be compressed and deduplicated, the TypeScript compiler - // sometimes generates source maps with duplicates in them. See Github issue - // #72 and bugzil.la/889492. - this._names = ArraySet.fromArray(names.map(String), true); - this._sources = ArraySet.fromArray(sources, true); - - this.sourceRoot = sourceRoot; - this.sourcesContent = sourcesContent; - this._mappings = mappings; - this.file = file; -} - -BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); -BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer; - -/** - * Create a BasicSourceMapConsumer from a SourceMapGenerator. - * - * @param SourceMapGenerator aSourceMap - * The source map that will be consumed. - * @returns BasicSourceMapConsumer - */ -BasicSourceMapConsumer.fromSourceMap = - function SourceMapConsumer_fromSourceMap(aSourceMap) { - var smc = Object.create(BasicSourceMapConsumer.prototype); - - var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); - var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); - smc.sourceRoot = aSourceMap._sourceRoot; - smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), - smc.sourceRoot); - smc.file = aSourceMap._file; - - // Because we are modifying the entries (by converting string sources and - // names to indices into the sources and names ArraySets), we have to make - // a copy of the entry or else bad things happen. Shared mutable state - // strikes again! See github issue #191. - - var generatedMappings = aSourceMap._mappings.toArray().slice(); - var destGeneratedMappings = smc.__generatedMappings = []; - var destOriginalMappings = smc.__originalMappings = []; - - for (var i = 0, length = generatedMappings.length; i < length; i++) { - var srcMapping = generatedMappings[i]; - var destMapping = new Mapping; - destMapping.generatedLine = srcMapping.generatedLine; - destMapping.generatedColumn = srcMapping.generatedColumn; - - if (srcMapping.source) { - destMapping.source = sources.indexOf(srcMapping.source); - destMapping.originalLine = srcMapping.originalLine; - destMapping.originalColumn = srcMapping.originalColumn; - - if (srcMapping.name) { - destMapping.name = names.indexOf(srcMapping.name); - } - - destOriginalMappings.push(destMapping); - } - - destGeneratedMappings.push(destMapping); - } - - quickSort(smc.__originalMappings, util.compareByOriginalPositions); - - return smc; - }; - -/** - * The version of the source mapping spec that we are consuming. - */ -BasicSourceMapConsumer.prototype._version = 3; - -/** - * The list of original sources. - */ -Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', { - get: function () { - return this._sources.toArray().map(function (s) { - return this.sourceRoot != null ? util.join(this.sourceRoot, s) : s; - }, this); - } -}); - -/** - * Provide the JIT with a nice shape / hidden class. - */ -function Mapping() { - this.generatedLine = 0; - this.generatedColumn = 0; - this.source = null; - this.originalLine = null; - this.originalColumn = null; - this.name = null; -} - -/** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). - */ -BasicSourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var length = aStr.length; - var index = 0; - var cachedSegments = {}; - var temp = {}; - var originalMappings = []; - var generatedMappings = []; - var mapping, str, segment, end, value; - - while (index < length) { - if (aStr.charAt(index) === ';') { - generatedLine++; - index++; - previousGeneratedColumn = 0; - } - else if (aStr.charAt(index) === ',') { - index++; - } - else { - mapping = new Mapping(); - mapping.generatedLine = generatedLine; - - // Because each offset is encoded relative to the previous one, - // many segments often have the same encoding. We can exploit this - // fact by caching the parsed variable length fields of each segment, - // allowing us to avoid a second parse if we encounter the same - // segment again. - for (end = index; end < length; end++) { - if (this._charIsMappingSeparator(aStr, end)) { - break; - } - } - str = aStr.slice(index, end); - - segment = cachedSegments[str]; - if (segment) { - index += str.length; - } else { - segment = []; - while (index < end) { - base64VLQ.decode(aStr, index, temp); - value = temp.value; - index = temp.rest; - segment.push(value); - } - - if (segment.length === 2) { - throw new Error('Found a source, but no line and column'); - } - - if (segment.length === 3) { - throw new Error('Found a source and line, but no column'); - } - - cachedSegments[str] = segment; - } - - // Generated column. - mapping.generatedColumn = previousGeneratedColumn + segment[0]; - previousGeneratedColumn = mapping.generatedColumn; - - if (segment.length > 1) { - // Original source. - mapping.source = previousSource + segment[1]; - previousSource += segment[1]; - - // Original line. - mapping.originalLine = previousOriginalLine + segment[2]; - previousOriginalLine = mapping.originalLine; - // Lines are stored 0-based - mapping.originalLine += 1; - - // Original column. - mapping.originalColumn = previousOriginalColumn + segment[3]; - previousOriginalColumn = mapping.originalColumn; - - if (segment.length > 4) { - // Original name. - mapping.name = previousName + segment[4]; - previousName += segment[4]; - } - } - - generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - originalMappings.push(mapping); - } - } - } - - quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated); - this.__generatedMappings = generatedMappings; - - quickSort(originalMappings, util.compareByOriginalPositions); - this.__originalMappings = originalMappings; - }; - -/** - * Find the mapping that best matches the hypothetical "needle" mapping that - * we are searching for in the given "haystack" of mappings. - */ -BasicSourceMapConsumer.prototype._findMapping = - function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, - aColumnName, aComparator, aBias) { - // To return the position we are searching for, we must first find the - // mapping for the given position and then return the opposite position it - // points to. Because the mappings are sorted, we can use binary search to - // find the best mapping. - - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' - + aNeedle[aLineName]); - } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' - + aNeedle[aColumnName]); - } - - return binarySearch.search(aNeedle, aMappings, aComparator, aBias); - }; - -/** - * Compute the last column for each generated mapping. The last column is - * inclusive. - */ -BasicSourceMapConsumer.prototype.computeColumnSpans = - function SourceMapConsumer_computeColumnSpans() { - for (var index = 0; index < this._generatedMappings.length; ++index) { - var mapping = this._generatedMappings[index]; - - // Mappings do not contain a field for the last generated columnt. We - // can come up with an optimistic estimate, however, by assuming that - // mappings are contiguous (i.e. given two consecutive mappings, the - // first mapping ends where the second one starts). - if (index + 1 < this._generatedMappings.length) { - var nextMapping = this._generatedMappings[index + 1]; - - if (mapping.generatedLine === nextMapping.generatedLine) { - mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1; - continue; - } - } - - // The last mapping for each line spans the entire line. - mapping.lastGeneratedColumn = Infinity; - } - }; - -/** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or - * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ -BasicSourceMapConsumer.prototype.originalPositionFor = - function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - - var index = this._findMapping( - needle, - this._generatedMappings, - "generatedLine", - "generatedColumn", - util.compareByGeneratedPositionsDeflated, - util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) - ); - - if (index >= 0) { - var mapping = this._generatedMappings[index]; - - if (mapping.generatedLine === needle.generatedLine) { - var source = util.getArg(mapping, 'source', null); - if (source !== null) { - source = this._sources.at(source); - if (this.sourceRoot != null) { - source = util.join(this.sourceRoot, source); - } - } - var name = util.getArg(mapping, 'name', null); - if (name !== null) { - name = this._names.at(name); - } - return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: name - }; - } - } - - return { - source: null, - line: null, - column: null, - name: null - }; - }; - -/** - * Return true if we have the source content for every source in the source - * map, false otherwise. - */ -BasicSourceMapConsumer.prototype.hasContentsOfAllSources = - function BasicSourceMapConsumer_hasContentsOfAllSources() { - if (!this.sourcesContent) { - return false; - } - return this.sourcesContent.length >= this._sources.size() && - !this.sourcesContent.some(function (sc) { return sc == null; }); - }; - -/** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * available. - */ -BasicSourceMapConsumer.prototype.sourceContentFor = - function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { - if (!this.sourcesContent) { - return null; - } - - if (this.sourceRoot != null) { - aSource = util.relative(this.sourceRoot, aSource); - } - - if (this._sources.has(aSource)) { - return this.sourcesContent[this._sources.indexOf(aSource)]; - } - - var url; - if (this.sourceRoot != null - && (url = util.urlParse(this.sourceRoot))) { - // XXX: file:// URIs and absolute paths lead to unexpected behavior for - // many users. We can help them out when they expect file:// URIs to - // behave like it would if they were running a local HTTP server. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. - var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); - if (url.scheme == "file" - && this._sources.has(fileUriAbsPath)) { - return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] - } - - if ((!url.path || url.path == "/") - && this._sources.has("/" + aSource)) { - return this.sourcesContent[this._sources.indexOf("/" + aSource)]; - } - } - - // This function is used recursively from - // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we - // don't want to throw if we can't find the source - we just want to - // return null, so we provide a flag to exit gracefully. - if (nullOnMissing) { - return null; - } - else { - throw new Error('"' + aSource + '" is not in the SourceMap.'); - } - }; - -/** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or - * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ -BasicSourceMapConsumer.prototype.generatedPositionFor = - function SourceMapConsumer_generatedPositionFor(aArgs) { - var source = util.getArg(aArgs, 'source'); - if (this.sourceRoot != null) { - source = util.relative(this.sourceRoot, source); - } - if (!this._sources.has(source)) { - return { - line: null, - column: null, - lastColumn: null - }; - } - source = this._sources.indexOf(source); - - var needle = { - source: source, - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') - }; - - var index = this._findMapping( - needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) - ); - - if (index >= 0) { - var mapping = this._originalMappings[index]; - - if (mapping.source === needle.source) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }; - } - } - - return { - line: null, - column: null, - lastColumn: null - }; - }; - -exports.BasicSourceMapConsumer = BasicSourceMapConsumer; - -/** - * An IndexedSourceMapConsumer instance represents a parsed source map which - * we can query for information. It differs from BasicSourceMapConsumer in - * that it takes "indexed" source maps (i.e. ones with a "sections" field) as - * input. - * - * The only parameter is a raw source map (either as a JSON string, or already - * parsed to an object). According to the spec for indexed source maps, they - * have the following attributes: - * - * - version: Which version of the source map spec this map is following. - * - file: Optional. The generated file this source map is associated with. - * - sections: A list of section definitions. - * - * Each value under the "sections" field has two fields: - * - offset: The offset into the original specified at which this section - * begins to apply, defined as an object with a "line" and "column" - * field. - * - map: A source map definition. This source map could also be indexed, - * but doesn't have to be. - * - * Instead of the "map" field, it's also possible to have a "url" field - * specifying a URL to retrieve a source map from, but that's currently - * unsupported. - * - * Here's an example source map, taken from the source map spec[0], but - * modified to omit a section which uses the "url" field. - * - * { - * version : 3, - * file: "app.js", - * sections: [{ - * offset: {line:100, column:10}, - * map: { - * version : 3, - * file: "section.js", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AAAA,E;;ABCDE;" - * } - * }], - * } - * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt - */ -function IndexedSourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - var version = util.getArg(sourceMap, 'version'); - var sections = util.getArg(sourceMap, 'sections'); - - if (version != this._version) { - throw new Error('Unsupported version: ' + version); - } - - this._sources = new ArraySet(); - this._names = new ArraySet(); - - var lastOffset = { - line: -1, - column: 0 - }; - this._sections = sections.map(function (s) { - if (s.url) { - // The url field will require support for asynchronicity. - // See https://github.com/mozilla/source-map/issues/16 - throw new Error('Support for url field in sections not implemented.'); - } - var offset = util.getArg(s, 'offset'); - var offsetLine = util.getArg(offset, 'line'); - var offsetColumn = util.getArg(offset, 'column'); - - if (offsetLine < lastOffset.line || - (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) { - throw new Error('Section offsets must be ordered and non-overlapping.'); - } - lastOffset = offset; - - return { - generatedOffset: { - // The offset fields are 0-based, but we use 1-based indices when - // encoding/decoding from VLQ. - generatedLine: offsetLine + 1, - generatedColumn: offsetColumn + 1 - }, - consumer: new SourceMapConsumer(util.getArg(s, 'map')) - } - }); -} - -IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); -IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer; - -/** - * The version of the source mapping spec that we are consuming. - */ -IndexedSourceMapConsumer.prototype._version = 3; - -/** - * The list of original sources. - */ -Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', { - get: function () { - var sources = []; - for (var i = 0; i < this._sections.length; i++) { - for (var j = 0; j < this._sections[i].consumer.sources.length; j++) { - sources.push(this._sections[i].consumer.sources[j]); - } - } - return sources; - } -}); - -/** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ -IndexedSourceMapConsumer.prototype.originalPositionFor = - function IndexedSourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - - // Find the section containing the generated position we're trying to map - // to an original position. - var sectionIndex = binarySearch.search(needle, this._sections, - function(needle, section) { - var cmp = needle.generatedLine - section.generatedOffset.generatedLine; - if (cmp) { - return cmp; - } - - return (needle.generatedColumn - - section.generatedOffset.generatedColumn); - }); - var section = this._sections[sectionIndex]; - - if (!section) { - return { - source: null, - line: null, - column: null, - name: null - }; - } - - return section.consumer.originalPositionFor({ - line: needle.generatedLine - - (section.generatedOffset.generatedLine - 1), - column: needle.generatedColumn - - (section.generatedOffset.generatedLine === needle.generatedLine - ? section.generatedOffset.generatedColumn - 1 - : 0), - bias: aArgs.bias - }); - }; - -/** - * Return true if we have the source content for every source in the source - * map, false otherwise. - */ -IndexedSourceMapConsumer.prototype.hasContentsOfAllSources = - function IndexedSourceMapConsumer_hasContentsOfAllSources() { - return this._sections.every(function (s) { - return s.consumer.hasContentsOfAllSources(); - }); - }; - -/** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * available. - */ -IndexedSourceMapConsumer.prototype.sourceContentFor = - function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; - - var content = section.consumer.sourceContentFor(aSource, true); - if (content) { - return content; - } - } - if (nullOnMissing) { - return null; - } - else { - throw new Error('"' + aSource + '" is not in the SourceMap.'); - } - }; - -/** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ -IndexedSourceMapConsumer.prototype.generatedPositionFor = - function IndexedSourceMapConsumer_generatedPositionFor(aArgs) { - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; - - // Only consider this section if the requested source is in the list of - // sources of the consumer. - if (section.consumer.sources.indexOf(util.getArg(aArgs, 'source')) === -1) { - continue; - } - var generatedPosition = section.consumer.generatedPositionFor(aArgs); - if (generatedPosition) { - var ret = { - line: generatedPosition.line + - (section.generatedOffset.generatedLine - 1), - column: generatedPosition.column + - (section.generatedOffset.generatedLine === generatedPosition.line - ? section.generatedOffset.generatedColumn - 1 - : 0) - }; - return ret; - } - } - - return { - line: null, - column: null - }; - }; - -/** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). - */ -IndexedSourceMapConsumer.prototype._parseMappings = - function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) { - this.__generatedMappings = []; - this.__originalMappings = []; - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; - var sectionMappings = section.consumer._generatedMappings; - for (var j = 0; j < sectionMappings.length; j++) { - var mapping = sectionMappings[j]; - - var source = section.consumer._sources.at(mapping.source); - if (section.consumer.sourceRoot !== null) { - source = util.join(section.consumer.sourceRoot, source); - } - this._sources.add(source); - source = this._sources.indexOf(source); - - var name = section.consumer._names.at(mapping.name); - this._names.add(name); - name = this._names.indexOf(name); - - // The mappings coming from the consumer for the section have - // generated positions relative to the start of the section, so we - // need to offset them to be relative to the start of the concatenated - // generated file. - var adjustedMapping = { - source: source, - generatedLine: mapping.generatedLine + - (section.generatedOffset.generatedLine - 1), - generatedColumn: mapping.generatedColumn + - (section.generatedOffset.generatedLine === mapping.generatedLine - ? section.generatedOffset.generatedColumn - 1 - : 0), - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: name - }; - - this.__generatedMappings.push(adjustedMapping); - if (typeof adjustedMapping.originalLine === 'number') { - this.__originalMappings.push(adjustedMapping); - } - } - } - - quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated); - quickSort(this.__originalMappings, util.compareByOriginalPositions); - }; - -exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; - - -/***/ }), -/* 670 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -exports.GREATEST_LOWER_BOUND = 1; -exports.LEAST_UPPER_BOUND = 2; - -/** - * Recursive implementation of binary search. - * - * @param aLow Indices here and lower do not contain the needle. - * @param aHigh Indices here and higher do not contain the needle. - * @param aNeedle The element being searched for. - * @param aHaystack The non-empty array being searched. - * @param aCompare Function which takes two elements and returns -1, 0, or 1. - * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or - * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - */ -function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) { - // This function terminates when one of the following is true: - // - // 1. We find the exact element we are looking for. - // - // 2. We did not find the exact element, but we can return the index of - // the next-closest element. - // - // 3. We did not find the exact element, and there is no next-closest - // element than the one we are searching for, so we return -1. - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid], true); - if (cmp === 0) { - // Found the element we are looking for. - return mid; - } - else if (cmp > 0) { - // Our needle is greater than aHaystack[mid]. - if (aHigh - mid > 1) { - // The element is in the upper half. - return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare, aBias); - } - - // The exact needle element was not found in this haystack. Determine if - // we are in termination case (3) or (2) and return the appropriate thing. - if (aBias == exports.LEAST_UPPER_BOUND) { - return aHigh < aHaystack.length ? aHigh : -1; - } else { - return mid; - } - } - else { - // Our needle is less than aHaystack[mid]. - if (mid - aLow > 1) { - // The element is in the lower half. - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias); - } - - // we are in termination case (3) or (2) and return the appropriate thing. - if (aBias == exports.LEAST_UPPER_BOUND) { - return mid; - } else { - return aLow < 0 ? -1 : aLow; - } - } -} - -/** - * This is an implementation of binary search which will always try and return - * the index of the closest element if there is no exact hit. This is because - * mappings between original and generated line/col pairs are single points, - * and there is an implicit region between each of them, so a miss just means - * that you aren't on the very start of a region. - * - * @param aNeedle The element you are looking for. - * @param aHaystack The array that is being searched. - * @param aCompare A function which takes the needle and an element in the - * array and returns -1, 0, or 1 depending on whether the needle is less - * than, equal to, or greater than the element, respectively. - * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or - * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'binarySearch.GREATEST_LOWER_BOUND'. - */ -exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { - if (aHaystack.length === 0) { - return -1; - } - - var index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, - aCompare, aBias || exports.GREATEST_LOWER_BOUND); - if (index < 0) { - return -1; - } - - // We have found either the exact element, or the next-closest element than - // the one we are searching for. However, there may be more than one such - // element. Make sure we always return the smallest of these. - while (index - 1 >= 0) { - if (aCompare(aHaystack[index], aHaystack[index - 1], true) !== 0) { - break; - } - --index; - } - - return index; -}; - - -/***/ }), -/* 671 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -// It turns out that some (most?) JavaScript engines don't self-host -// `Array.prototype.sort`. This makes sense because C++ will likely remain -// faster than JS when doing raw CPU-intensive sorting. However, when using a -// custom comparator function, calling back and forth between the VM's C++ and -// JIT'd JS is rather slow *and* loses JIT type information, resulting in -// worse generated code for the comparator function than would be optimal. In -// fact, when sorting with a comparator, these costs outweigh the benefits of -// sorting in C++. By using our own JS-implemented Quick Sort (below), we get -// a ~3500ms mean speed-up in `bench/bench.html`. - -/** - * Swap the elements indexed by `x` and `y` in the array `ary`. - * - * @param {Array} ary - * The array. - * @param {Number} x - * The index of the first item. - * @param {Number} y - * The index of the second item. - */ -function swap(ary, x, y) { - var temp = ary[x]; - ary[x] = ary[y]; - ary[y] = temp; -} - -/** - * Returns a random integer within the range `low .. high` inclusive. - * - * @param {Number} low - * The lower bound on the range. - * @param {Number} high - * The upper bound on the range. - */ -function randomIntInRange(low, high) { - return Math.round(low + (Math.random() * (high - low))); -} - -/** - * The Quick Sort algorithm. - * - * @param {Array} ary - * An array to sort. - * @param {function} comparator - * Function to use to compare two items. - * @param {Number} p - * Start index of the array - * @param {Number} r - * End index of the array - */ -function doQuickSort(ary, comparator, p, r) { - // If our lower bound is less than our upper bound, we (1) partition the - // array into two pieces and (2) recurse on each half. If it is not, this is - // the empty array and our base case. - - if (p < r) { - // (1) Partitioning. - // - // The partitioning chooses a pivot between `p` and `r` and moves all - // elements that are less than or equal to the pivot to the before it, and - // all the elements that are greater than it after it. The effect is that - // once partition is done, the pivot is in the exact place it will be when - // the array is put in sorted order, and it will not need to be moved - // again. This runs in O(n) time. - - // Always choose a random pivot so that an input array which is reverse - // sorted does not cause O(n^2) running time. - var pivotIndex = randomIntInRange(p, r); - var i = p - 1; - - swap(ary, pivotIndex, r); - var pivot = ary[r]; - - // Immediately after `j` is incremented in this loop, the following hold - // true: - // - // * Every element in `ary[p .. i]` is less than or equal to the pivot. - // - // * Every element in `ary[i+1 .. j-1]` is greater than the pivot. - for (var j = p; j < r; j++) { - if (comparator(ary[j], pivot) <= 0) { - i += 1; - swap(ary, i, j); - } - } - - swap(ary, i + 1, j); - var q = i + 1; - - // (2) Recurse on each half. - - doQuickSort(ary, comparator, p, q - 1); - doQuickSort(ary, comparator, q + 1, r); - } -} - -/** - * Sort the given array in-place with the given comparator function. - * - * @param {Array} ary - * An array to sort. - * @param {function} comparator - * Function to use to compare two items. - */ -exports.quickSort = function (ary, comparator) { - doQuickSort(ary, comparator, 0, ary.length - 1); -}; - - -/***/ }), -/* 672 */ -/***/ (function(module, exports, __webpack_require__) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var SourceMapGenerator = __webpack_require__(663).SourceMapGenerator; -var util = __webpack_require__(666); - -// Matches a Windows-style `\r\n` newline or a `\n` newline used by all other -// operating systems these days (capturing the result). -var REGEX_NEWLINE = /(\r?\n)/; - -// Newline character code for charCodeAt() comparisons -var NEWLINE_CODE = 10; - -// Private symbol for identifying `SourceNode`s when multiple versions of -// the source-map library are loaded. This MUST NOT CHANGE across -// versions! -var isSourceNode = "$$$isSourceNode$$$"; - -/** - * SourceNodes provide a way to abstract over interpolating/concatenating - * snippets of generated JavaScript source code while maintaining the line and - * column information associated with the original source code. - * - * @param aLine The original line number. - * @param aColumn The original column number. - * @param aSource The original source's filename. - * @param aChunks Optional. An array of strings which are snippets of - * generated JS, or other SourceNodes. - * @param aName The original identifier. - */ -function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine == null ? null : aLine; - this.column = aColumn == null ? null : aColumn; - this.source = aSource == null ? null : aSource; - this.name = aName == null ? null : aName; - this[isSourceNode] = true; - if (aChunks != null) this.add(aChunks); -} - -/** - * Creates a SourceNode from generated code and a SourceMapConsumer. - * - * @param aGeneratedCode The generated code - * @param aSourceMapConsumer The SourceMap for the generated code - * @param aRelativePath Optional. The path that relative sources in the - * SourceMapConsumer should be relative to. - */ -SourceNode.fromStringWithSourceMap = - function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) { - // The SourceNode we want to fill with the generated code - // and the SourceMap - var node = new SourceNode(); - - // All even indices of this array are one line of the generated code, - // while all odd indices are the newlines between two adjacent lines - // (since `REGEX_NEWLINE` captures its match). - // Processed fragments are accessed by calling `shiftNextLine`. - var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); - var remainingLinesIndex = 0; - var shiftNextLine = function() { - var lineContents = getNextLine(); - // The last line of a file might not have a newline. - var newLine = getNextLine() || ""; - return lineContents + newLine; - - function getNextLine() { - return remainingLinesIndex < remainingLines.length ? - remainingLines[remainingLinesIndex++] : undefined; - } - }; - - // We need to remember the position of "remainingLines" - var lastGeneratedLine = 1, lastGeneratedColumn = 0; - - // The generate SourceNodes we need a code range. - // To extract it current and last mapping is used. - // Here we store the last mapping. - var lastMapping = null; - - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping !== null) { - // We add the code from "lastMapping" to "mapping": - // First check if there is a new line in between. - if (lastGeneratedLine < mapping.generatedLine) { - // Associate first line with "lastMapping" - addMappingWithCode(lastMapping, shiftNextLine()); - lastGeneratedLine++; - lastGeneratedColumn = 0; - // The remaining code is added without mapping - } else { - // There is no new line in between. - // Associate the code between "lastGeneratedColumn" and - // "mapping.generatedColumn" with "lastMapping" - var nextLine = remainingLines[remainingLinesIndex]; - var code = nextLine.substr(0, mapping.generatedColumn - - lastGeneratedColumn); - remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn - - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - // No more remaining code, continue - lastMapping = mapping; - return; - } - } - // We add the generated code until the first mapping - // to the SourceNode without any mapping. - // Each line is added as separate string. - while (lastGeneratedLine < mapping.generatedLine) { - node.add(shiftNextLine()); - lastGeneratedLine++; - } - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[remainingLinesIndex]; - node.add(nextLine.substr(0, mapping.generatedColumn)); - remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - lastMapping = mapping; - }, this); - // We have processed all mappings. - if (remainingLinesIndex < remainingLines.length) { - if (lastMapping) { - // Associate the remaining code in the current line with "lastMapping" - addMappingWithCode(lastMapping, shiftNextLine()); - } - // and add the remaining lines without any mapping - node.add(remainingLines.splice(remainingLinesIndex).join("")); - } - - // Copy sourcesContent into SourceNode - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - if (aRelativePath != null) { - sourceFile = util.join(aRelativePath, sourceFile); - } - node.setSourceContent(sourceFile, content); - } - }); - - return node; - - function addMappingWithCode(mapping, code) { - if (mapping === null || mapping.source === undefined) { - node.add(code); - } else { - var source = aRelativePath - ? util.join(aRelativePath, mapping.source) - : mapping.source; - node.add(new SourceNode(mapping.originalLine, - mapping.originalColumn, - source, - code, - mapping.name)); - } - } - }; - -/** - * Add a chunk of generated JS to this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ -SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); - } - else if (aChunk[isSourceNode] || typeof aChunk === "string") { - if (aChunk) { - this.children.push(aChunk); - } - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; -}; - -/** - * Add a chunk of generated JS to the beginning of this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ -SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length-1; i >= 0; i--) { - this.prepend(aChunk[i]); - } - } - else if (aChunk[isSourceNode] || typeof aChunk === "string") { - this.children.unshift(aChunk); - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; -}; - -/** - * Walk over the tree of JS snippets in this node and its children. The - * walking function is called once for each snippet of JS and is passed that - * snippet and the its original associated source's line/column location. - * - * @param aFn The traversal function. - */ -SourceNode.prototype.walk = function SourceNode_walk(aFn) { - var chunk; - for (var i = 0, len = this.children.length; i < len; i++) { - chunk = this.children[i]; - if (chunk[isSourceNode]) { - chunk.walk(aFn); - } - else { - if (chunk !== '') { - aFn(chunk, { source: this.source, - line: this.line, - column: this.column, - name: this.name }); - } - } - } -}; - -/** - * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between - * each of `this.children`. - * - * @param aSep The separator. - */ -SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len-1; i++) { - newChildren.push(this.children[i]); - newChildren.push(aSep); - } - newChildren.push(this.children[i]); - this.children = newChildren; - } - return this; -}; - -/** - * Call String.prototype.replace on the very right-most source snippet. Useful - * for trimming whitespace from the end of a source node, etc. - * - * @param aPattern The pattern to replace. - * @param aReplacement The thing to replace the pattern with. - */ -SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild[isSourceNode]) { - lastChild.replaceRight(aPattern, aReplacement); - } - else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); - } - else { - this.children.push(''.replace(aPattern, aReplacement)); - } - return this; -}; - -/** - * Set the source content for a source file. This will be added to the SourceMapGenerator - * in the sourcesContent field. - * - * @param aSourceFile The filename of the source file - * @param aSourceContent The content of the source file - */ -SourceNode.prototype.setSourceContent = - function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; - -/** - * Walk over the tree of SourceNodes. The walking function is called for each - * source file content and is passed the filename and source content. - * - * @param aFn The traversal function. - */ -SourceNode.prototype.walkSourceContents = - function SourceNode_walkSourceContents(aFn) { - for (var i = 0, len = this.children.length; i < len; i++) { - if (this.children[i][isSourceNode]) { - this.children[i].walkSourceContents(aFn); - } - } - - var sources = Object.keys(this.sourceContents); - for (var i = 0, len = sources.length; i < len; i++) { - aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); - } - }; - -/** - * Return the string representation of this source node. Walks over the tree - * and concatenates all the various snippets together to one string. - */ -SourceNode.prototype.toString = function SourceNode_toString() { - var str = ""; - this.walk(function (chunk) { - str += chunk; - }); - return str; -}; - -/** - * Returns the string representation of this source node along with a source - * map. - */ -SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: "", - line: 1, - column: 0 - }; - var map = new SourceMapGenerator(aArgs); - var sourceMappingActive = false; - var lastOriginalSource = null; - var lastOriginalLine = null; - var lastOriginalColumn = null; - var lastOriginalName = null; - this.walk(function (chunk, original) { - generated.code += chunk; - if (original.source !== null - && original.line !== null - && original.column !== null) { - if(lastOriginalSource !== original.source - || lastOriginalLine !== original.line - || lastOriginalColumn !== original.column - || lastOriginalName !== original.name) { - map.addMapping({ - source: original.source, - original: { - line: original.line, - column: original.column - }, - generated: { - line: generated.line, - column: generated.column - }, - name: original.name - }); - } - lastOriginalSource = original.source; - lastOriginalLine = original.line; - lastOriginalColumn = original.column; - lastOriginalName = original.name; - sourceMappingActive = true; - } else if (sourceMappingActive) { - map.addMapping({ - generated: { - line: generated.line, - column: generated.column - } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - for (var idx = 0, length = chunk.length; idx < length; idx++) { - if (chunk.charCodeAt(idx) === NEWLINE_CODE) { - generated.line++; - generated.column = 0; - // Mappings end at eol - if (idx + 1 === length) { - lastOriginalSource = null; - sourceMappingActive = false; - } else if (sourceMappingActive) { - map.addMapping({ - source: original.source, - original: { - line: original.line, - column: original.column - }, - generated: { - line: generated.line, - column: generated.column - }, - name: original.name - }); - } - } else { - generated.column++; - } - } - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); - - return { code: generated.code, map: map }; -}; - -exports.SourceNode = SourceNode; - - -/***/ }), -/* 673 */ -/***/ (function(module, exports, __webpack_require__) { - -var sourceMappingURL = __webpack_require__(674) - -var resolveUrl = __webpack_require__(675) -var decodeUriComponent = __webpack_require__(676) -var urix = __webpack_require__(678) -var atob = __webpack_require__(679) - - - -function callbackAsync(callback, error, result) { - setImmediate(function() { callback(error, result) }) -} - -function parseMapToJSON(string, data) { - try { - return JSON.parse(string.replace(/^\)\]\}'/, "")) - } catch (error) { - error.sourceMapData = data - throw error - } -} - -function readSync(read, url, data) { - var readUrl = decodeUriComponent(url) - try { - return String(read(readUrl)) - } catch (error) { - error.sourceMapData = data - throw error - } -} - - - -function resolveSourceMap(code, codeUrl, read, callback) { - var mapData - try { - mapData = resolveSourceMapHelper(code, codeUrl) - } catch (error) { - return callbackAsync(callback, error) - } - if (!mapData || mapData.map) { - return callbackAsync(callback, null, mapData) - } - var readUrl = decodeUriComponent(mapData.url) - read(readUrl, function(error, result) { - if (error) { - error.sourceMapData = mapData - return callback(error) - } - mapData.map = String(result) - try { - mapData.map = parseMapToJSON(mapData.map, mapData) - } catch (error) { - return callback(error) - } - callback(null, mapData) - }) -} - -function resolveSourceMapSync(code, codeUrl, read) { - var mapData = resolveSourceMapHelper(code, codeUrl) - if (!mapData || mapData.map) { - return mapData - } - mapData.map = readSync(read, mapData.url, mapData) - mapData.map = parseMapToJSON(mapData.map, mapData) - return mapData -} - -var dataUriRegex = /^data:([^,;]*)(;[^,;]*)*(?:,(.*))?$/ - -/** - * The media type for JSON text is application/json. - * - * {@link https://tools.ietf.org/html/rfc8259#section-11 | IANA Considerations } - * - * `text/json` is non-standard media type - */ -var jsonMimeTypeRegex = /^(?:application|text)\/json$/ - -/** - * JSON text exchanged between systems that are not part of a closed ecosystem - * MUST be encoded using UTF-8. - * - * {@link https://tools.ietf.org/html/rfc8259#section-8.1 | Character Encoding} - */ -var jsonCharacterEncoding = "utf-8" - -function base64ToBuf(b64) { - var binStr = atob(b64) - var len = binStr.length - var arr = new Uint8Array(len) - for (var i = 0; i < len; i++) { - arr[i] = binStr.charCodeAt(i) - } - return arr -} - -function decodeBase64String(b64) { - if (typeof TextDecoder === "undefined" || typeof Uint8Array === "undefined") { - return atob(b64) - } - var buf = base64ToBuf(b64); - // Note: `decoder.decode` method will throw a `DOMException` with the - // `"EncodingError"` value when an coding error is found. - var decoder = new TextDecoder(jsonCharacterEncoding, {fatal: true}) - return decoder.decode(buf); -} - -function resolveSourceMapHelper(code, codeUrl) { - codeUrl = urix(codeUrl) - - var url = sourceMappingURL.getFrom(code) - if (!url) { - return null - } - - var dataUri = url.match(dataUriRegex) - if (dataUri) { - var mimeType = dataUri[1] || "text/plain" - var lastParameter = dataUri[2] || "" - var encoded = dataUri[3] || "" - var data = { - sourceMappingURL: url, - url: null, - sourcesRelativeTo: codeUrl, - map: encoded - } - if (!jsonMimeTypeRegex.test(mimeType)) { - var error = new Error("Unuseful data uri mime type: " + mimeType) - error.sourceMapData = data - throw error - } - try { - data.map = parseMapToJSON( - lastParameter === ";base64" ? decodeBase64String(encoded) : decodeURIComponent(encoded), - data - ) - } catch (error) { - error.sourceMapData = data - throw error - } - return data - } - - var mapUrl = resolveUrl(codeUrl, url) - return { - sourceMappingURL: url, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } -} - - - -function resolveSources(map, mapUrl, read, options, callback) { - if (typeof options === "function") { - callback = options - options = {} - } - var pending = map.sources ? map.sources.length : 0 - var result = { - sourcesResolved: [], - sourcesContent: [] - } - - if (pending === 0) { - callbackAsync(callback, null, result) - return - } - - var done = function() { - pending-- - if (pending === 0) { - callback(null, result) - } - } - - resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { - result.sourcesResolved[index] = fullUrl - if (typeof sourceContent === "string") { - result.sourcesContent[index] = sourceContent - callbackAsync(done, null) - } else { - var readUrl = decodeUriComponent(fullUrl) - read(readUrl, function(error, source) { - result.sourcesContent[index] = error ? error : String(source) - done() - }) - } - }) -} - -function resolveSourcesSync(map, mapUrl, read, options) { - var result = { - sourcesResolved: [], - sourcesContent: [] - } - - if (!map.sources || map.sources.length === 0) { - return result - } - - resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { - result.sourcesResolved[index] = fullUrl - if (read !== null) { - if (typeof sourceContent === "string") { - result.sourcesContent[index] = sourceContent - } else { - var readUrl = decodeUriComponent(fullUrl) - try { - result.sourcesContent[index] = String(read(readUrl)) - } catch (error) { - result.sourcesContent[index] = error - } - } - } - }) - - return result -} - -var endingSlash = /\/?$/ - -function resolveSourcesHelper(map, mapUrl, options, fn) { - options = options || {} - mapUrl = urix(mapUrl) - var fullUrl - var sourceContent - var sourceRoot - for (var index = 0, len = map.sources.length; index < len; index++) { - sourceRoot = null - if (typeof options.sourceRoot === "string") { - sourceRoot = options.sourceRoot - } else if (typeof map.sourceRoot === "string" && options.sourceRoot !== false) { - sourceRoot = map.sourceRoot - } - // If the sourceRoot is the empty string, it is equivalent to not setting - // the property at all. - if (sourceRoot === null || sourceRoot === '') { - fullUrl = resolveUrl(mapUrl, map.sources[index]) - } else { - // Make sure that the sourceRoot ends with a slash, so that `/scripts/subdir` becomes - // `/scripts/subdir/`, not `/scripts/`. Pointing to a file as source root - // does not make sense. - fullUrl = resolveUrl(mapUrl, sourceRoot.replace(endingSlash, "/"), map.sources[index]) - } - sourceContent = (map.sourcesContent || [])[index] - fn(fullUrl, sourceContent, index) - } -} - - - -function resolve(code, codeUrl, read, options, callback) { - if (typeof options === "function") { - callback = options - options = {} - } - if (code === null) { - var mapUrl = codeUrl - var data = { - sourceMappingURL: null, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } - var readUrl = decodeUriComponent(mapUrl) - read(readUrl, function(error, result) { - if (error) { - error.sourceMapData = data - return callback(error) - } - data.map = String(result) - try { - data.map = parseMapToJSON(data.map, data) - } catch (error) { - return callback(error) - } - _resolveSources(data) - }) - } else { - resolveSourceMap(code, codeUrl, read, function(error, mapData) { - if (error) { - return callback(error) - } - if (!mapData) { - return callback(null, null) - } - _resolveSources(mapData) - }) - } - - function _resolveSources(mapData) { - resolveSources(mapData.map, mapData.sourcesRelativeTo, read, options, function(error, result) { - if (error) { - return callback(error) - } - mapData.sourcesResolved = result.sourcesResolved - mapData.sourcesContent = result.sourcesContent - callback(null, mapData) - }) - } -} - -function resolveSync(code, codeUrl, read, options) { - var mapData - if (code === null) { - var mapUrl = codeUrl - mapData = { - sourceMappingURL: null, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } - mapData.map = readSync(read, mapUrl, mapData) - mapData.map = parseMapToJSON(mapData.map, mapData) - } else { - mapData = resolveSourceMapSync(code, codeUrl, read) - if (!mapData) { - return null - } - } - var result = resolveSourcesSync(mapData.map, mapData.sourcesRelativeTo, read, options) - mapData.sourcesResolved = result.sourcesResolved - mapData.sourcesContent = result.sourcesContent - return mapData -} - - - -module.exports = { - resolveSourceMap: resolveSourceMap, - resolveSourceMapSync: resolveSourceMapSync, - resolveSources: resolveSources, - resolveSourcesSync: resolveSourcesSync, - resolve: resolve, - resolveSync: resolveSync, - parseMapToJSON: parseMapToJSON -} - - -/***/ }), -/* 674 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -void (function(root, factory) { - if (true) { - !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : - __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) - } else {} -}(this, function() { - - var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/ - - var regex = RegExp( - "(?:" + - "/\\*" + - "(?:\\s*\r?\n(?://)?)?" + - "(?:" + innerRegex.source + ")" + - "\\s*" + - "\\*/" + - "|" + - "//(?:" + innerRegex.source + ")" + - ")" + - "\\s*" - ) - - return { - - regex: regex, - _innerRegex: innerRegex, - - getFrom: function(code) { - var match = code.match(regex) - return (match ? match[1] || match[2] || "" : null) - }, - - existsIn: function(code) { - return regex.test(code) - }, - - removeFrom: function(code) { - return code.replace(regex, "") - }, - - insertBefore: function(code, string) { - var match = code.match(regex) - if (match) { - return code.slice(0, match.index) + string + code.slice(match.index) - } else { - return code + string - } - } - } - -})); - - -/***/ }), -/* 675 */ -/***/ (function(module, exports, __webpack_require__) { - -var url = __webpack_require__(252) - -function resolveUrl(/* ...urls */) { - return Array.prototype.reduce.call(arguments, function(resolved, nextUrl) { - return url.resolve(resolved, nextUrl) - }) -} - -module.exports = resolveUrl - - -/***/ }), -/* 676 */ -/***/ (function(module, exports, __webpack_require__) { - -var decodeUriComponent = __webpack_require__(677) - -function customDecodeUriComponent(string) { - // `decodeUriComponent` turns `+` into ` `, but that's not wanted. - return decodeUriComponent(string.replace(/\+/g, "%2B")) -} - -module.exports = customDecodeUriComponent - - -/***/ }), -/* 677 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var token = '%[a-f0-9]{2}'; -var singleMatcher = new RegExp('(' + token + ')|([^%]+?)', 'gi'); -var multiMatcher = new RegExp('(' + token + ')+', 'gi'); - -function decodeComponents(components, split) { - try { - // Try to decode the entire string first - return [decodeURIComponent(components.join(''))]; - } catch (err) { - // Do nothing - } - - if (components.length === 1) { - return components; - } - - split = split || 1; - - // Split the array in 2 parts - var left = components.slice(0, split); - var right = components.slice(split); - - return Array.prototype.concat.call([], decodeComponents(left), decodeComponents(right)); -} - -function decode(input) { - try { - return decodeURIComponent(input); - } catch (err) { - var tokens = input.match(singleMatcher) || []; - - for (var i = 1; i < tokens.length; i++) { - input = decodeComponents(tokens, i).join(''); - - tokens = input.match(singleMatcher) || []; - } - - return input; - } -} - -function customDecodeURIComponent(input) { - // Keep track of all the replacements and prefill the map with the `BOM` - var replaceMap = { - '%FE%FF': '\uFFFD\uFFFD', - '%FF%FE': '\uFFFD\uFFFD' - }; - - var match = multiMatcher.exec(input); - while (match) { - try { - // Decode as big chunks as possible - replaceMap[match[0]] = decodeURIComponent(match[0]); - } catch (err) { - var result = decode(match[0]); - - if (result !== match[0]) { - replaceMap[match[0]] = result; - } - } - - match = multiMatcher.exec(input); - } - - // Add `%C2` at the end of the map to make sure it does not replace the combinator before everything else - replaceMap['%C2'] = '\uFFFD'; - - var entries = Object.keys(replaceMap); - - for (var i = 0; i < entries.length; i++) { - // Replace all decoded components - var key = entries[i]; - input = input.replace(new RegExp(key, 'g'), replaceMap[key]); - } - - return input; -} - -module.exports = function (encodedURI) { - if (typeof encodedURI !== 'string') { - throw new TypeError('Expected `encodedURI` to be of type `string`, got `' + typeof encodedURI + '`'); - } - - try { - encodedURI = encodedURI.replace(/\+/g, ' '); - - // Try the built in decoder first - return decodeURIComponent(encodedURI); - } catch (err) { - // Fallback to a more advanced decoder - return customDecodeURIComponent(encodedURI); - } -}; - - -/***/ }), -/* 678 */ -/***/ (function(module, exports, __webpack_require__) { - -// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -var path = __webpack_require__(4) - -"use strict" - -function urix(aPath) { - if (path.sep === "\\") { - return aPath - .replace(/\\/g, "/") - .replace(/^[a-z]:\/?/i, "/") - } - return aPath -} - -module.exports = urix - - -/***/ }), -/* 679 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function atob(str) { - return Buffer.from(str, 'base64').toString('binary'); -} - -module.exports = atob.atob = atob; - - -/***/ }), -/* 680 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var fs = __webpack_require__(134); -var path = __webpack_require__(4); -var define = __webpack_require__(645); -var utils = __webpack_require__(660); - -/** - * Expose `mixin()`. - * This code is based on `source-maps-support.js` in reworkcss/css - * https://github.com/reworkcss/css/blob/master/lib/stringify/source-map-support.js - * Copyright (c) 2012 TJ Holowaychuk - */ - -module.exports = mixin; - -/** - * Mixin source map support into `compiler`. - * - * @param {Object} `compiler` - * @api public - */ - -function mixin(compiler) { - define(compiler, '_comment', compiler.comment); - compiler.map = new utils.SourceMap.SourceMapGenerator(); - compiler.position = { line: 1, column: 1 }; - compiler.content = {}; - compiler.files = {}; - - for (var key in exports) { - define(compiler, key, exports[key]); - } -} - -/** - * Update position. - * - * @param {String} str - */ - -exports.updatePosition = function(str) { - var lines = str.match(/\n/g); - if (lines) this.position.line += lines.length; - var i = str.lastIndexOf('\n'); - this.position.column = ~i ? str.length - i : this.position.column + str.length; -}; - -/** - * Emit `str` with `position`. - * - * @param {String} str - * @param {Object} [pos] - * @return {String} - */ - -exports.emit = function(str, node) { - var position = node.position || {}; - var source = position.source; - if (source) { - if (position.filepath) { - source = utils.unixify(position.filepath); - } - - this.map.addMapping({ - source: source, - generated: { - line: this.position.line, - column: Math.max(this.position.column - 1, 0) - }, - original: { - line: position.start.line, - column: position.start.column - 1 - } - }); - - if (position.content) { - this.addContent(source, position); - } - if (position.filepath) { - this.addFile(source, position); - } - - this.updatePosition(str); - this.output += str; - } - return str; -}; - -/** - * Adds a file to the source map output if it has not already been added - * @param {String} `file` - * @param {Object} `pos` - */ - -exports.addFile = function(file, position) { - if (typeof position.content !== 'string') return; - if (Object.prototype.hasOwnProperty.call(this.files, file)) return; - this.files[file] = position.content; -}; - -/** - * Adds a content source to the source map output if it has not already been added - * @param {String} `source` - * @param {Object} `position` - */ - -exports.addContent = function(source, position) { - if (typeof position.content !== 'string') return; - if (Object.prototype.hasOwnProperty.call(this.content, source)) return; - this.map.setSourceContent(source, position.content); -}; - -/** - * Applies any original source maps to the output and embeds the source file - * contents in the source map. - */ - -exports.applySourceMaps = function() { - Object.keys(this.files).forEach(function(file) { - var content = this.files[file]; - this.map.setSourceContent(file, content); - - if (this.options.inputSourcemaps === true) { - var originalMap = utils.sourceMapResolve.resolveSync(content, file, fs.readFileSync); - if (originalMap) { - var map = new utils.SourceMap.SourceMapConsumer(originalMap.map); - var relativeTo = originalMap.sourcesRelativeTo; - this.map.applySourceMap(map, file, utils.unixify(path.dirname(relativeTo))); - } - } - }, this); -}; - -/** - * Process comments, drops sourceMap comments. - * @param {Object} node - */ - -exports.comment = function(node) { - if (/^# sourceMappingURL=/.test(node.comment)) { - return this.emit('', node.position); - } - return this._comment(node); -}; - - -/***/ }), -/* 681 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var use = __webpack_require__(653); -var util = __webpack_require__(112); -var Cache = __webpack_require__(682); -var define = __webpack_require__(645); -var debug = __webpack_require__(654)('snapdragon:parser'); -var Position = __webpack_require__(683); -var utils = __webpack_require__(660); - -/** - * Create a new `Parser` with the given `input` and `options`. - * @param {String} `input` - * @param {Object} `options` - * @api public - */ - -function Parser(options) { - debug('initializing', __filename); - this.options = utils.extend({source: 'string'}, options); - this.init(this.options); - use(this); -} - -/** - * Prototype methods - */ - -Parser.prototype = { - constructor: Parser, - - init: function(options) { - this.orig = ''; - this.input = ''; - this.parsed = ''; - - this.column = 1; - this.line = 1; - - this.regex = new Cache(); - this.errors = this.errors || []; - this.parsers = this.parsers || {}; - this.types = this.types || []; - this.sets = this.sets || {}; - this.fns = this.fns || []; - this.currentType = 'root'; - - var pos = this.position(); - this.bos = pos({type: 'bos', val: ''}); - - this.ast = { - type: 'root', - errors: this.errors, - nodes: [this.bos] - }; - - define(this.bos, 'parent', this.ast); - this.nodes = [this.ast]; - - this.count = 0; - this.setCount = 0; - this.stack = []; - }, - - /** - * Throw a formatted error with the cursor column and `msg`. - * @param {String} `msg` Message to use in the Error. - */ - - error: function(msg, node) { - var pos = node.position || {start: {column: 0, line: 0}}; - var line = pos.start.line; - var column = pos.start.column; - var source = this.options.source; - - var message = source + ' : ' + msg; - var err = new Error(message); - err.source = source; - err.reason = msg; - err.pos = pos; - - if (this.options.silent) { - this.errors.push(err); - } else { - throw err; - } - }, - - /** - * Define a non-enumberable property on the `Parser` instance. - * - * ```js - * parser.define('foo', 'bar'); - * ``` - * @name .define - * @param {String} `key` propery name - * @param {any} `val` property value - * @return {Object} Returns the Parser instance for chaining. - * @api public - */ - - define: function(key, val) { - define(this, key, val); - return this; - }, - - /** - * Mark position and patch `node.position`. - */ - - position: function() { - var start = { line: this.line, column: this.column }; - var self = this; - - return function(node) { - define(node, 'position', new Position(start, self)); - return node; - }; - }, - - /** - * Set parser `name` with the given `fn` - * @param {String} `name` - * @param {Function} `fn` - * @api public - */ - - set: function(type, fn) { - if (this.types.indexOf(type) === -1) { - this.types.push(type); - } - this.parsers[type] = fn.bind(this); - return this; - }, - - /** - * Get parser `name` - * @param {String} `name` - * @api public - */ - - get: function(name) { - return this.parsers[name]; - }, - - /** - * Push a `token` onto the `type` stack. - * - * @param {String} `type` - * @return {Object} `token` - * @api public - */ - - push: function(type, token) { - this.sets[type] = this.sets[type] || []; - this.count++; - this.stack.push(token); - return this.sets[type].push(token); - }, - - /** - * Pop a token off of the `type` stack - * @param {String} `type` - * @returns {Object} Returns a token - * @api public - */ - - pop: function(type) { - this.sets[type] = this.sets[type] || []; - this.count--; - this.stack.pop(); - return this.sets[type].pop(); - }, - - /** - * Return true if inside a `stack` node. Types are `braces`, `parens` or `brackets`. - * - * @param {String} `type` - * @return {Boolean} - * @api public - */ - - isInside: function(type) { - this.sets[type] = this.sets[type] || []; - return this.sets[type].length > 0; - }, - - /** - * Return true if `node` is the given `type`. - * - * ```js - * parser.isType(node, 'brace'); - * ``` - * @param {Object} `node` - * @param {String} `type` - * @return {Boolean} - * @api public - */ - - isType: function(node, type) { - return node && node.type === type; - }, - - /** - * Get the previous AST node - * @return {Object} - */ - - prev: function(n) { - return this.stack.length > 0 - ? utils.last(this.stack, n) - : utils.last(this.nodes, n); - }, - - /** - * Update line and column based on `str`. - */ - - consume: function(len) { - this.input = this.input.substr(len); - }, - - /** - * Update column based on `str`. - */ - - updatePosition: function(str, len) { - var lines = str.match(/\n/g); - if (lines) this.line += lines.length; - var i = str.lastIndexOf('\n'); - this.column = ~i ? len - i : this.column + len; - this.parsed += str; - this.consume(len); - }, - - /** - * Match `regex`, return captures, and update the cursor position by `match[0]` length. - * @param {RegExp} `regex` - * @return {Object} - */ - - match: function(regex) { - var m = regex.exec(this.input); - if (m) { - this.updatePosition(m[0], m[0].length); - return m; - } - }, - - /** - * Capture `type` with the given regex. - * @param {String} `type` - * @param {RegExp} `regex` - * @return {Function} - */ - - capture: function(type, regex) { - if (typeof regex === 'function') { - return this.set.apply(this, arguments); - } - - this.regex.set(type, regex); - this.set(type, function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(regex); - if (!m || !m[0]) return; - - var prev = this.prev(); - var node = pos({ - type: type, - val: m[0], - parsed: parsed, - rest: this.input - }); - - if (m[1]) { - node.inner = m[1]; - } - - define(node, 'inside', this.stack.length > 0); - define(node, 'parent', prev); - prev.nodes.push(node); - }.bind(this)); - return this; - }, - - /** - * Create a parser with open and close for parens, - * brackets or braces - */ - - capturePair: function(type, openRegex, closeRegex, fn) { - this.sets[type] = this.sets[type] || []; - - /** - * Open - */ - - this.set(type + '.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(openRegex); - if (!m || !m[0]) return; - - var val = m[0]; - this.setCount++; - this.specialChars = true; - var open = pos({ - type: type + '.open', - val: val, - rest: this.input - }); - - if (typeof m[1] !== 'undefined') { - open.inner = m[1]; - } - - var prev = this.prev(); - var node = pos({ - type: type, - nodes: [open] - }); - - define(node, 'rest', this.input); - define(node, 'parsed', parsed); - define(node, 'prefix', m[1]); - define(node, 'parent', prev); - define(open, 'parent', node); - - if (typeof fn === 'function') { - fn.call(this, open, node); - } - - this.push(type, node); - prev.nodes.push(node); - }); - - /** - * Close - */ - - this.set(type + '.close', function() { - var pos = this.position(); - var m = this.match(closeRegex); - if (!m || !m[0]) return; - - var parent = this.pop(type); - var node = pos({ - type: type + '.close', - rest: this.input, - suffix: m[1], - val: m[0] - }); - - if (!this.isType(parent, type)) { - if (this.options.strict) { - throw new Error('missing opening "' + type + '"'); - } - - this.setCount--; - node.escaped = true; - return node; - } - - if (node.suffix === '\\') { - parent.escaped = true; - node.escaped = true; - } - - parent.nodes.push(node); - define(node, 'parent', parent); - }); - - return this; - }, - - /** - * Capture end-of-string - */ - - eos: function() { - var pos = this.position(); - if (this.input) return; - var prev = this.prev(); - - while (prev.type !== 'root' && !prev.visited) { - if (this.options.strict === true) { - throw new SyntaxError('invalid syntax:' + util.inspect(prev, null, 2)); - } - - if (!hasDelims(prev)) { - prev.parent.escaped = true; - prev.escaped = true; - } - - visit(prev, function(node) { - if (!hasDelims(node.parent)) { - node.parent.escaped = true; - node.escaped = true; - } - }); - - prev = prev.parent; - } - - var tok = pos({ - type: 'eos', - val: this.append || '' - }); - - define(tok, 'parent', this.ast); - return tok; - }, - - /** - * Run parsers to advance the cursor position - */ - - next: function() { - var parsed = this.parsed; - var len = this.types.length; - var idx = -1; - var tok; - - while (++idx < len) { - if ((tok = this.parsers[this.types[idx]].call(this))) { - define(tok, 'rest', this.input); - define(tok, 'parsed', parsed); - this.last = tok; - return tok; - } - } - }, - - /** - * Parse the given string. - * @return {Array} - */ - - parse: function(input) { - if (typeof input !== 'string') { - throw new TypeError('expected a string'); - } - - this.init(this.options); - this.orig = input; - this.input = input; - var self = this; - - function parse() { - // check input before calling `.next()` - input = self.input; - - // get the next AST ndoe - var node = self.next(); - if (node) { - var prev = self.prev(); - if (prev) { - define(node, 'parent', prev); - if (prev.nodes) { - prev.nodes.push(node); - } - } - - if (self.sets.hasOwnProperty(prev.type)) { - self.currentType = prev.type; - } - } - - // if we got here but input is not changed, throw an error - if (self.input && input === self.input) { - throw new Error('no parsers registered for: "' + self.input.slice(0, 5) + '"'); - } - } - - while (this.input) parse(); - if (this.stack.length && this.options.strict) { - var node = this.stack.pop(); - throw this.error('missing opening ' + node.type + ': "' + this.orig + '"'); - } - - var eos = this.eos(); - var tok = this.prev(); - if (tok.type !== 'eos') { - this.ast.nodes.push(eos); - } - - return this.ast; - } -}; - -/** - * Visit `node` with the given `fn` - */ - -function visit(node, fn) { - if (!node.visited) { - define(node, 'visited', true); - return node.nodes ? mapVisit(node.nodes, fn) : fn(node); - } - return node; -} - -/** - * Map visit over array of `nodes`. - */ - -function mapVisit(nodes, fn) { - var len = nodes.length; - var idx = -1; - while (++idx < len) { - visit(nodes[idx], fn); - } -} - -function hasOpen(node) { - return node.nodes && node.nodes[0].type === (node.type + '.open'); -} - -function hasClose(node) { - return node.nodes && utils.last(node.nodes).type === (node.type + '.close'); -} - -function hasDelims(node) { - return hasOpen(node) && hasClose(node); -} - -/** - * Expose `Parser` - */ - -module.exports = Parser; - - -/***/ }), -/* 682 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * map-cache - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -var hasOwn = Object.prototype.hasOwnProperty; - -/** - * Expose `MapCache` - */ - -module.exports = MapCache; - -/** - * Creates a cache object to store key/value pairs. - * - * ```js - * var cache = new MapCache(); - * ``` - * - * @api public - */ - -function MapCache(data) { - this.__data__ = data || {}; -} - -/** - * Adds `value` to `key` on the cache. - * - * ```js - * cache.set('foo', 'bar'); - * ``` - * - * @param {String} `key` The key of the value to cache. - * @param {*} `value` The value to cache. - * @returns {Object} Returns the `Cache` object for chaining. - * @api public - */ - -MapCache.prototype.set = function mapSet(key, value) { - if (key !== '__proto__') { - this.__data__[key] = value; - } - return this; -}; - -/** - * Gets the cached value for `key`. - * - * ```js - * cache.get('foo'); - * //=> 'bar' - * ``` - * - * @param {String} `key` The key of the value to get. - * @returns {*} Returns the cached value. - * @api public - */ - -MapCache.prototype.get = function mapGet(key) { - return key === '__proto__' ? undefined : this.__data__[key]; -}; - -/** - * Checks if a cached value for `key` exists. - * - * ```js - * cache.has('foo'); - * //=> true - * ``` - * - * @param {String} `key` The key of the entry to check. - * @returns {Boolean} Returns `true` if an entry for `key` exists, else `false`. - * @api public - */ - -MapCache.prototype.has = function mapHas(key) { - return key !== '__proto__' && hasOwn.call(this.__data__, key); -}; - -/** - * Removes `key` and its value from the cache. - * - * ```js - * cache.del('foo'); - * ``` - * @title .del - * @param {String} `key` The key of the value to remove. - * @returns {Boolean} Returns `true` if the entry was removed successfully, else `false`. - * @api public - */ - -MapCache.prototype.del = function mapDelete(key) { - return this.has(key) && delete this.__data__[key]; -}; - - -/***/ }), -/* 683 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var define = __webpack_require__(645); - -/** - * Store position for a node - */ - -module.exports = function Position(start, parser) { - this.start = start; - this.end = { line: parser.line, column: parser.column }; - define(this, 'content', parser.orig); - define(this, 'source', parser.options.source); -}; - - -/***/ }), -/* 684 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var nanomatch = __webpack_require__(685); -var extglob = __webpack_require__(695); - -module.exports = function(snapdragon) { - var compilers = snapdragon.compiler.compilers; - var opts = snapdragon.options; - - // register nanomatch compilers - snapdragon.use(nanomatch.compilers); - - // get references to some specific nanomatch compilers before they - // are overridden by the extglob and/or custom compilers - var escape = compilers.escape; - var qmark = compilers.qmark; - var slash = compilers.slash; - var star = compilers.star; - var text = compilers.text; - var plus = compilers.plus; - var dot = compilers.dot; - - // register extglob compilers or escape exglobs if disabled - if (opts.extglob === false || opts.noext === true) { - snapdragon.compiler.use(escapeExtglobs); - } else { - snapdragon.use(extglob.compilers); - } - - snapdragon.use(function() { - this.options.star = this.options.star || function(/*node*/) { - return '[^\\\\/]*?'; - }; - }); - - // custom micromatch compilers - snapdragon.compiler - - // reset referenced compiler - .set('dot', dot) - .set('escape', escape) - .set('plus', plus) - .set('slash', slash) - .set('qmark', qmark) - .set('star', star) - .set('text', text); -}; - -function escapeExtglobs(compiler) { - compiler.set('paren', function(node) { - var val = ''; - visit(node, function(tok) { - if (tok.val) val += (/^\W/.test(tok.val) ? '\\' : '') + tok.val; - }); - return this.emit(val, node); - }); - - /** - * Visit `node` with the given `fn` - */ - - function visit(node, fn) { - return node.nodes ? mapVisit(node.nodes, fn) : fn(node); - } - - /** - * Map visit over array of `nodes`. - */ - - function mapVisit(nodes, fn) { - var len = nodes.length; - var idx = -1; - while (++idx < len) { - visit(nodes[idx], fn); - } - } -} - - -/***/ }), -/* 685 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var util = __webpack_require__(112); -var toRegex = __webpack_require__(582); -var extend = __webpack_require__(595); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(686); -var parsers = __webpack_require__(687); -var cache = __webpack_require__(688); -var utils = __webpack_require__(690); -var MAX_LENGTH = 1024 * 64; - -/** - * The main function takes a list of strings and one or more - * glob patterns to use for matching. - * - * ```js - * var nm = require('nanomatch'); - * nm(list, patterns[, options]); - * - * console.log(nm(['a.js', 'a.txt'], ['*.js'])); - * //=> [ 'a.js' ] - * ``` - * @param {Array} `list` A list of strings to match - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of matches - * @summary false - * @api public - */ - -function nanomatch(list, patterns, options) { - patterns = utils.arrayify(patterns); - list = utils.arrayify(list); - - var len = patterns.length; - if (list.length === 0 || len === 0) { - return []; - } - - if (len === 1) { - return nanomatch.match(list, patterns[0], options); - } - - var negated = false; - var omit = []; - var keep = []; - var idx = -1; - - while (++idx < len) { - var pattern = patterns[idx]; - - if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { - omit.push.apply(omit, nanomatch.match(list, pattern.slice(1), options)); - negated = true; - } else { - keep.push.apply(keep, nanomatch.match(list, pattern, options)); - } - } - - // minimatch.match parity - if (negated && keep.length === 0) { - if (options && options.unixify === false) { - keep = list.slice(); - } else { - var unixify = utils.unixify(options); - for (var i = 0; i < list.length; i++) { - keep.push(unixify(list[i])); - } - } - } - - var matches = utils.diff(keep, omit); - if (!options || options.nodupes !== false) { - return utils.unique(matches); - } - - return matches; -} - -/** - * Similar to the main function, but `pattern` must be a string. - * - * ```js - * var nm = require('nanomatch'); - * nm.match(list, pattern[, options]); - * - * console.log(nm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); - * //=> ['a.a', 'a.aa'] - * ``` - * @param {Array} `list` Array of strings to match - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of matches - * @api public - */ - -nanomatch.match = function(list, pattern, options) { - if (Array.isArray(pattern)) { - throw new TypeError('expected pattern to be a string'); - } - - var unixify = utils.unixify(options); - var isMatch = memoize('match', pattern, options, nanomatch.matcher); - var matches = []; - - list = utils.arrayify(list); - var len = list.length; - var idx = -1; - - while (++idx < len) { - var ele = list[idx]; - if (ele === pattern || isMatch(ele)) { - matches.push(utils.value(ele, unixify, options)); - } - } - - // if no options were passed, uniquify results and return - if (typeof options === 'undefined') { - return utils.unique(matches); - } - - if (matches.length === 0) { - if (options.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - if (options.nonull === true || options.nullglob === true) { - return [options.unescape ? utils.unescape(pattern) : pattern]; - } - } - - // if `opts.ignore` was defined, diff ignored list - if (options.ignore) { - matches = nanomatch.not(matches, options.ignore, options); - } - - return options.nodupes !== false ? utils.unique(matches) : matches; -}; - -/** - * Returns true if the specified `string` matches the given glob `pattern`. - * - * ```js - * var nm = require('nanomatch'); - * nm.isMatch(string, pattern[, options]); - * - * console.log(nm.isMatch('a.a', '*.a')); - * //=> true - * console.log(nm.isMatch('a.b', '*.a')); - * //=> false - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the string matches the glob pattern. - * @api public - */ - -nanomatch.isMatch = function(str, pattern, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (utils.isEmptyString(str) || utils.isEmptyString(pattern)) { - return false; - } - - var equals = utils.equalsPattern(options); - if (equals(str)) { - return true; - } - - var isMatch = memoize('isMatch', pattern, options, nanomatch.matcher); - return isMatch(str); -}; - -/** - * Returns true if some of the elements in the given `list` match any of the - * given glob `patterns`. - * - * ```js - * var nm = require('nanomatch'); - * nm.some(list, patterns[, options]); - * - * console.log(nm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // true - * console.log(nm.some(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. Returns as soon as the first match is found. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -nanomatch.some = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - - for (var i = 0; i < list.length; i++) { - if (nanomatch(list[i], patterns, options).length === 1) { - return true; - } - } - - return false; -}; - -/** - * Returns true if every element in the given `list` matches - * at least one of the given glob `patterns`. - * - * ```js - * var nm = require('nanomatch'); - * nm.every(list, patterns[, options]); - * - * console.log(nm.every('foo.js', ['foo.js'])); - * // true - * console.log(nm.every(['foo.js', 'bar.js'], ['*.js'])); - * // true - * console.log(nm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // false - * console.log(nm.every(['foo.js'], ['*.js', '!foo.js'])); - * // false - * ``` - * @param {String|Array} `list` The string or array of strings to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -nanomatch.every = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - - for (var i = 0; i < list.length; i++) { - if (nanomatch(list[i], patterns, options).length !== 1) { - return false; - } - } - - return true; -}; - -/** - * Returns true if **any** of the given glob `patterns` - * match the specified `string`. - * - * ```js - * var nm = require('nanomatch'); - * nm.any(string, patterns[, options]); - * - * console.log(nm.any('a.a', ['b.*', '*.a'])); - * //=> true - * console.log(nm.any('a.a', 'b.*')); - * //=> false - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -nanomatch.any = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (utils.isEmptyString(str) || utils.isEmptyString(patterns)) { - return false; - } - - if (typeof patterns === 'string') { - patterns = [patterns]; - } - - for (var i = 0; i < patterns.length; i++) { - if (nanomatch.isMatch(str, patterns[i], options)) { - return true; - } - } - return false; -}; - -/** - * Returns true if **all** of the given `patterns` - * match the specified string. - * - * ```js - * var nm = require('nanomatch'); - * nm.all(string, patterns[, options]); - * - * console.log(nm.all('foo.js', ['foo.js'])); - * // true - * - * console.log(nm.all('foo.js', ['*.js', '!foo.js'])); - * // false - * - * console.log(nm.all('foo.js', ['*.js', 'foo.js'])); - * // true - * - * console.log(nm.all('foo.js', ['*.js', 'f*', '*o*', '*o.js'])); - * // true - * ``` - * @param {String|Array} `str` The string to test. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ - -nanomatch.all = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (typeof patterns === 'string') { - patterns = [patterns]; - } - - for (var i = 0; i < patterns.length; i++) { - if (!nanomatch.isMatch(str, patterns[i], options)) { - return false; - } - } - return true; -}; - -/** - * Returns a list of strings that _**do not match any**_ of the given `patterns`. - * - * ```js - * var nm = require('nanomatch'); - * nm.not(list, patterns[, options]); - * - * console.log(nm.not(['a.a', 'b.b', 'c.c'], '*.a')); - * //=> ['b.b', 'c.c'] - * ``` - * @param {Array} `list` Array of strings to match. - * @param {String|Array} `patterns` One or more glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Array} Returns an array of strings that **do not match** the given patterns. - * @api public - */ - -nanomatch.not = function(list, patterns, options) { - var opts = extend({}, options); - var ignore = opts.ignore; - delete opts.ignore; - - list = utils.arrayify(list); - - var matches = utils.diff(list, nanomatch(list, patterns, opts)); - if (ignore) { - matches = utils.diff(matches, nanomatch(list, ignore)); - } - - return opts.nodupes !== false ? utils.unique(matches) : matches; -}; - -/** - * Returns true if the given `string` contains the given pattern. Similar - * to [.isMatch](#isMatch) but the pattern can match any part of the string. - * - * ```js - * var nm = require('nanomatch'); - * nm.contains(string, pattern[, options]); - * - * console.log(nm.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(nm.contains('aa/bb/cc', '*d')); - * //=> false - * ``` - * @param {String} `str` The string to match. - * @param {String|Array} `patterns` Glob pattern to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns true if the patter matches any part of `str`. - * @api public - */ - -nanomatch.contains = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (typeof patterns === 'string') { - if (utils.isEmptyString(str) || utils.isEmptyString(patterns)) { - return false; - } - - var equals = utils.equalsPattern(patterns, options); - if (equals(str)) { - return true; - } - var contains = utils.containsPattern(patterns, options); - if (contains(str)) { - return true; - } - } - - var opts = extend({}, options, {contains: true}); - return nanomatch.any(str, patterns, opts); -}; - -/** - * Returns true if the given pattern and options should enable - * the `matchBase` option. - * @return {Boolean} - * @api private - */ - -nanomatch.matchBase = function(pattern, options) { - if (pattern && pattern.indexOf('/') !== -1 || !options) return false; - return options.basename === true || options.matchBase === true; -}; - -/** - * Filter the keys of the given object with the given `glob` pattern - * and `options`. Does not attempt to match nested keys. If you need this feature, - * use [glob-object][] instead. - * - * ```js - * var nm = require('nanomatch'); - * nm.matchKeys(object, patterns[, options]); - * - * var obj = { aa: 'a', ab: 'b', ac: 'c' }; - * console.log(nm.matchKeys(obj, '*b')); - * //=> { ab: 'b' } - * ``` - * @param {Object} `object` The object with keys to filter. - * @param {String|Array} `patterns` One or more glob patterns to use for matching. - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Object} Returns an object with only keys that match the given patterns. - * @api public - */ - -nanomatch.matchKeys = function(obj, patterns, options) { - if (!utils.isObject(obj)) { - throw new TypeError('expected the first argument to be an object'); - } - var keys = nanomatch(Object.keys(obj), patterns, options); - return utils.pick(obj, keys); -}; - -/** - * Returns a memoized matcher function from the given glob `pattern` and `options`. - * The returned function takes a string to match as its only argument and returns - * true if the string is a match. - * - * ```js - * var nm = require('nanomatch'); - * nm.matcher(pattern[, options]); - * - * var isMatch = nm.matcher('*.!(*a)'); - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.b')); - * //=> true - * ``` - * @param {String} `pattern` Glob pattern - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {Function} Returns a matcher function. - * @api public - */ - -nanomatch.matcher = function matcher(pattern, options) { - if (utils.isEmptyString(pattern)) { - return function() { - return false; - }; - } - - if (Array.isArray(pattern)) { - return compose(pattern, options, matcher); - } - - // if pattern is a regex - if (pattern instanceof RegExp) { - return test(pattern); - } - - // if pattern is invalid - if (!utils.isString(pattern)) { - throw new TypeError('expected pattern to be an array, string or regex'); - } - - // if pattern is a non-glob string - if (!utils.hasSpecialChars(pattern)) { - if (options && options.nocase === true) { - pattern = pattern.toLowerCase(); - } - return utils.matchPath(pattern, options); - } - - // if pattern is a glob string - var re = nanomatch.makeRe(pattern, options); - - // if `options.matchBase` or `options.basename` is defined - if (nanomatch.matchBase(pattern, options)) { - return utils.matchBasename(re, options); - } - - function test(regex) { - var equals = utils.equalsPattern(options); - var unixify = utils.unixify(options); - - return function(str) { - if (equals(str)) { - return true; - } - - if (regex.test(unixify(str))) { - return true; - } - return false; - }; - } - - // create matcher function - var matcherFn = test(re); - // set result object from compiler on matcher function, - // as a non-enumerable property. useful for debugging - utils.define(matcherFn, 'result', re.result); - return matcherFn; -}; - -/** - * Returns an array of matches captured by `pattern` in `string, or - * `null` if the pattern did not match. - * - * ```js - * var nm = require('nanomatch'); - * nm.capture(pattern, string[, options]); - * - * console.log(nm.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(nm.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `pattern` Glob pattern to use for matching. - * @param {String} `string` String to match - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns an array of captures if the string matches the glob pattern, otherwise `null`. - * @api public - */ - -nanomatch.capture = function(pattern, str, options) { - var re = nanomatch.makeRe(pattern, extend({capture: true}, options)); - var unixify = utils.unixify(options); - - function match() { - return function(string) { - var match = re.exec(unixify(string)); - if (!match) { - return null; - } - - return match.slice(1); - }; - } - - var capture = memoize('capture', pattern, options, match); - return capture(str); -}; - -/** - * Create a regular expression from the given glob `pattern`. - * - * ```js - * var nm = require('nanomatch'); - * nm.makeRe(pattern[, options]); - * - * console.log(nm.makeRe('*.js')); - * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ - * ``` - * @param {String} `pattern` A glob pattern to convert to regex. - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {RegExp} Returns a regex created from the given pattern. - * @api public - */ - -nanomatch.makeRe = function(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - function makeRe() { - var opts = utils.extend({wrap: false}, options); - var result = nanomatch.create(pattern, opts); - var regex = toRegex(result.output, opts); - utils.define(regex, 'result', result); - return regex; - } - - return memoize('makeRe', pattern, options, makeRe); -}; - -/** - * Parses the given glob `pattern` and returns an object with the compiled `output` - * and optional source `map`. - * - * ```js - * var nm = require('nanomatch'); - * nm.create(pattern[, options]); - * - * console.log(nm.create('abc/*.js')); - * // { options: { source: 'string', sourcemap: true }, - * // state: {}, - * // compilers: - * // { ... }, - * // output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: - * // [ ... ], - * // dot: false, - * // input: 'abc/*.js' }, - * // parsingErrors: [], - * // map: - * // { version: 3, - * // sources: [ 'string' ], - * // names: [], - * // mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE', - * // sourcesContent: [ 'abc/*.js' ] }, - * // position: { line: 1, column: 28 }, - * // content: {}, - * // files: {}, - * // idx: 6 } - * ``` - * @param {String} `pattern` Glob pattern to parse and compile. - * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed. - * @return {Object} Returns an object with the parsed AST, compiled string and optional source map. - * @api public - */ - -nanomatch.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - function create() { - return nanomatch.compile(nanomatch.parse(pattern, options), options); - } - return memoize('create', pattern, options, create); -}; - -/** - * Parse the given `str` with the given `options`. - * - * ```js - * var nm = require('nanomatch'); - * nm.parse(pattern[, options]); - * - * var ast = nm.parse('a/{b,c}/d'); - * console.log(ast); - * // { type: 'root', - * // errors: [], - * // input: 'a/{b,c}/d', - * // nodes: - * // [ { type: 'bos', val: '' }, - * // { type: 'text', val: 'a/' }, - * // { type: 'brace', - * // nodes: - * // [ { type: 'brace.open', val: '{' }, - * // { type: 'text', val: 'b,c' }, - * // { type: 'brace.close', val: '}' } ] }, - * // { type: 'text', val: '/d' }, - * // { type: 'eos', val: '' } ] } - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {Object} Returns an AST - * @api public - */ - -nanomatch.parse = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - - function parse() { - var snapdragon = utils.instantiate(null, options); - parsers(snapdragon, options); - - var ast = snapdragon.parse(pattern, options); - utils.define(ast, 'snapdragon', snapdragon); - ast.input = pattern; - return ast; - } - - return memoize('parse', pattern, options, parse); -}; - -/** - * Compile the given `ast` or string with the given `options`. - * - * ```js - * var nm = require('nanomatch'); - * nm.compile(ast[, options]); - * - * var ast = nm.parse('a/{b,c}/d'); - * console.log(nm.compile(ast)); - * // { options: { source: 'string' }, - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // brace: [Function], - * // 'brace.open': [Function], - * // text: [Function], - * // 'brace.close': [Function] }, - * // output: [ 'a/(b|c)/d' ], - * // ast: - * // { ... }, - * // parsingErrors: [] } - * ``` - * @param {Object|String} `ast` - * @param {Object} `options` - * @return {Object} Returns an object that has an `output` property with the compiled string. - * @api public - */ - -nanomatch.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = nanomatch.parse(ast, options); - } - - function compile() { - var snapdragon = utils.instantiate(ast, options); - compilers(snapdragon, options); - return snapdragon.compile(ast, options); - } - - return memoize('compile', ast.input, options, compile); -}; - -/** - * Clear the regex cache. - * - * ```js - * nm.clearCache(); - * ``` - * @api public - */ - -nanomatch.clearCache = function() { - nanomatch.cache.__data__ = {}; -}; - -/** - * Compose a matcher function with the given patterns. - * This allows matcher functions to be compiled once and - * called multiple times. - */ - -function compose(patterns, options, matcher) { - var matchers; - - return memoize('compose', String(patterns), options, function() { - return function(file) { - // delay composition until it's invoked the first time, - // after that it won't be called again - if (!matchers) { - matchers = []; - for (var i = 0; i < patterns.length; i++) { - matchers.push(matcher(patterns[i], options)); - } - } - - var len = matchers.length; - while (len--) { - if (matchers[len](file) === true) { - return true; - } - } - return false; - }; - }); -} - -/** - * Memoize a generated regex or function. A unique key is generated - * from the `type` (usually method name), the `pattern`, and - * user-defined options. - */ - -function memoize(type, pattern, options, fn) { - var key = utils.createKey(type + '=' + pattern, options); - - if (options && options.cache === false) { - return fn(pattern, options); - } - - if (cache.has(type, key)) { - return cache.get(type, key); - } - - var val = fn(pattern, options); - cache.set(type, key, val); - return val; -} - -/** - * Expose compiler, parser and cache on `nanomatch` - */ - -nanomatch.compilers = compilers; -nanomatch.parsers = parsers; -nanomatch.cache = cache; - -/** - * Expose `nanomatch` - * @type {Function} - */ - -module.exports = nanomatch; - - -/***/ }), -/* 686 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** -* Nanomatch compilers -*/ - -module.exports = function(nanomatch, options) { - function slash() { - if (options && typeof options.slash === 'string') { - return options.slash; - } - if (options && typeof options.slash === 'function') { - return options.slash.call(nanomatch); - } - return '\\\\/'; - } - - function star() { - if (options && typeof options.star === 'string') { - return options.star; - } - if (options && typeof options.star === 'function') { - return options.star.call(nanomatch); - } - return '[^' + slash() + ']*?'; - } - - var ast = nanomatch.ast = nanomatch.parser.ast; - ast.state = nanomatch.parser.state; - nanomatch.compiler.state = ast.state; - nanomatch.compiler - - /** - * Negation / escaping - */ - - .set('not', function(node) { - var prev = this.prev(); - if (this.options.nonegate === true || prev.type !== 'bos') { - return this.emit('\\' + node.val, node); - } - return this.emit(node.val, node); - }) - .set('escape', function(node) { - if (this.options.unescape && /^[-\w_.]/.test(node.val)) { - return this.emit(node.val, node); - } - return this.emit('\\' + node.val, node); - }) - .set('quoted', function(node) { - return this.emit(node.val, node); - }) - - /** - * Regex - */ - - .set('dollar', function(node) { - if (node.parent.type === 'bracket') { - return this.emit(node.val, node); - } - return this.emit('\\' + node.val, node); - }) - - /** - * Dot: "." - */ - - .set('dot', function(node) { - if (node.dotfiles === true) this.dotfiles = true; - return this.emit('\\' + node.val, node); - }) - - /** - * Slashes: "/" and "\" - */ - - .set('backslash', function(node) { - return this.emit(node.val, node); - }) - .set('slash', function(node, nodes, i) { - var val = '[' + slash() + ']'; - var parent = node.parent; - var prev = this.prev(); - - // set "node.hasSlash" to true on all ancestor parens nodes - while (parent.type === 'paren' && !parent.hasSlash) { - parent.hasSlash = true; - parent = parent.parent; - } - - if (prev.addQmark) { - val += '?'; - } - - // word boundary - if (node.rest.slice(0, 2) === '\\b') { - return this.emit(val, node); - } - - // globstars - if (node.parsed === '**' || node.parsed === './**') { - this.output = '(?:' + this.output; - return this.emit(val + ')?', node); - } - - // negation - if (node.parsed === '!**' && this.options.nonegate !== true) { - return this.emit(val + '?\\b', node); - } - return this.emit(val, node); - }) - - /** - * Square brackets - */ - - .set('bracket', function(node) { - var close = node.close; - var open = !node.escaped ? '[' : '\\['; - var negated = node.negated; - var inner = node.inner; - var val = node.val; - - if (node.escaped === true) { - inner = inner.replace(/\\?(\W)/g, '\\$1'); - negated = ''; - } - - if (inner === ']-') { - inner = '\\]\\-'; - } - - if (negated && inner.indexOf('.') === -1) { - inner += '.'; - } - if (negated && inner.indexOf('/') === -1) { - inner += '/'; - } - - val = open + negated + inner + close; - return this.emit(val, node); - }) - - /** - * Square: "[.]" (only matches a single character in brackets) - */ - - .set('square', function(node) { - var val = (/^\W/.test(node.val) ? '\\' : '') + node.val; - return this.emit(val, node); - }) - - /** - * Question mark: "?" - */ - - .set('qmark', function(node) { - var prev = this.prev(); - // don't use "slash" variable so that we always avoid - // matching backslashes and slashes with a qmark - var val = '[^.\\\\/]'; - if (this.options.dot || (prev.type !== 'bos' && prev.type !== 'slash')) { - val = '[^\\\\/]'; - } - - if (node.parsed.slice(-1) === '(') { - var ch = node.rest.charAt(0); - if (ch === '!' || ch === '=' || ch === ':') { - return this.emit(node.val, node); - } - } - - if (node.val.length > 1) { - val += '{' + node.val.length + '}'; - } - return this.emit(val, node); - }) - - /** - * Plus - */ - - .set('plus', function(node) { - var prev = node.parsed.slice(-1); - if (prev === ']' || prev === ')') { - return this.emit(node.val, node); - } - if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) { - return this.emit('\\+', node); - } - var ch = this.output.slice(-1); - if (/\w/.test(ch) && !node.inside) { - return this.emit('+\\+?', node); - } - return this.emit('+', node); - }) - - /** - * globstar: '**' - */ - - .set('globstar', function(node, nodes, i) { - if (!this.output) { - this.state.leadingGlobstar = true; - } - - var prev = this.prev(); - var before = this.prev(2); - var next = this.next(); - var after = this.next(2); - var type = prev.type; - var val = node.val; - - if (prev.type === 'slash' && next.type === 'slash') { - if (before.type === 'text') { - this.output += '?'; - - if (after.type !== 'text') { - this.output += '\\b'; - } - } - } - - var parsed = node.parsed; - if (parsed.charAt(0) === '!') { - parsed = parsed.slice(1); - } - - var isInside = node.isInside.paren || node.isInside.brace; - if (parsed && type !== 'slash' && type !== 'bos' && !isInside) { - val = star(); - } else { - val = this.options.dot !== true - ? '(?:(?!(?:[' + slash() + ']|^)\\.).)*?' - : '(?:(?!(?:[' + slash() + ']|^)(?:\\.{1,2})($|[' + slash() + ']))(?!\\.{2}).)*?'; - } - - if ((type === 'slash' || type === 'bos') && this.options.dot !== true) { - val = '(?!\\.)' + val; - } - - if (prev.type === 'slash' && next.type === 'slash' && before.type !== 'text') { - if (after.type === 'text' || after.type === 'star') { - node.addQmark = true; - } - } - - if (this.options.capture) { - val = '(' + val + ')'; - } - - return this.emit(val, node); - }) - - /** - * Star: "*" - */ - - .set('star', function(node, nodes, i) { - var prior = nodes[i - 2] || {}; - var prev = this.prev(); - var next = this.next(); - var type = prev.type; - - function isStart(n) { - return n.type === 'bos' || n.type === 'slash'; - } - - if (this.output === '' && this.options.contains !== true) { - this.output = '(?![' + slash() + '])'; - } - - if (type === 'bracket' && this.options.bash === false) { - var str = next && next.type === 'bracket' ? star() : '*?'; - if (!prev.nodes || prev.nodes[1].type !== 'posix') { - return this.emit(str, node); - } - } - - var prefix = !this.dotfiles && type !== 'text' && type !== 'escape' - ? (this.options.dot ? '(?!(?:^|[' + slash() + '])\\.{1,2}(?:$|[' + slash() + ']))' : '(?!\\.)') - : ''; - - if (isStart(prev) || (isStart(prior) && type === 'not')) { - if (prefix !== '(?!\\.)') { - prefix += '(?!(\\.{2}|\\.[' + slash() + ']))(?=.)'; - } else { - prefix += '(?=.)'; - } - } else if (prefix === '(?!\\.)') { - prefix = ''; - } - - if (prev.type === 'not' && prior.type === 'bos' && this.options.dot === true) { - this.output = '(?!\\.)' + this.output; - } - - var output = prefix + star(); - if (this.options.capture) { - output = '(' + output + ')'; - } - - return this.emit(output, node); - }) - - /** - * Text - */ - - .set('text', function(node) { - return this.emit(node.val, node); - }) - - /** - * End-of-string - */ - - .set('eos', function(node) { - var prev = this.prev(); - var val = node.val; - - this.output = '(?:\\.[' + slash() + '](?=.))?' + this.output; - if (this.state.metachar && prev.type !== 'qmark' && prev.type !== 'slash') { - val += (this.options.contains ? '[' + slash() + ']?' : '(?:[' + slash() + ']|$)'); - } - - return this.emit(val, node); - }); - - /** - * Allow custom compilers to be passed on options - */ - - if (options && typeof options.compilers === 'function') { - options.compilers(nanomatch.compiler); - } -}; - - - -/***/ }), -/* 687 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var regexNot = __webpack_require__(599); -var toRegex = __webpack_require__(582); - -/** - * Characters to use in negation regex (we want to "not" match - * characters that are matched by other parsers) - */ - -var cached; -var NOT_REGEX = '[\\[!*+?$^"\'.\\\\/]+'; -var not = createTextRegex(NOT_REGEX); - -/** - * Nanomatch parsers - */ - -module.exports = function(nanomatch, options) { - var parser = nanomatch.parser; - var opts = parser.options; - - parser.state = { - slashes: 0, - paths: [] - }; - - parser.ast.state = parser.state; - parser - - /** - * Beginning-of-string - */ - - .capture('prefix', function() { - if (this.parsed) return; - var m = this.match(/^\.[\\/]/); - if (!m) return; - this.state.strictOpen = !!this.options.strictOpen; - this.state.addPrefix = true; - }) - - /** - * Escape: "\\." - */ - - .capture('escape', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^(?:\\(.)|([$^]))/); - if (!m) return; - - return pos({ - type: 'escape', - val: m[2] || m[1] - }); - }) - - /** - * Quoted strings - */ - - .capture('quoted', function() { - var pos = this.position(); - var m = this.match(/^["']/); - if (!m) return; - - var quote = m[0]; - if (this.input.indexOf(quote) === -1) { - return pos({ - type: 'escape', - val: quote - }); - } - - var tok = advanceTo(this.input, quote); - this.consume(tok.len); - - return pos({ - type: 'quoted', - val: tok.esc - }); - }) - - /** - * Negations: "!" - */ - - .capture('not', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(this.notRegex || /^!+/); - if (!m) return; - var val = m[0]; - - var isNegated = (val.length % 2) === 1; - if (parsed === '' && !isNegated) { - val = ''; - } - - // if nothing has been parsed, we know `!` is at the start, - // so we need to wrap the result in a negation regex - if (parsed === '' && isNegated && this.options.nonegate !== true) { - this.bos.val = '(?!^(?:'; - this.append = ')$).*'; - val = ''; - } - return pos({ - type: 'not', - val: val - }); - }) - - /** - * Dot: "." - */ - - .capture('dot', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\.+/); - if (!m) return; - - var val = m[0]; - this.state.dot = val === '.' && (parsed === '' || parsed.slice(-1) === '/'); - - return pos({ - type: 'dot', - dotfiles: this.state.dot, - val: val - }); - }) - - /** - * Plus: "+" - */ - - .capture('plus', /^\+(?!\()/) - - /** - * Question mark: "?" - */ - - .capture('qmark', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\?+(?!\()/); - if (!m) return; - - this.state.metachar = true; - this.state.qmark = true; - - return pos({ - type: 'qmark', - parsed: parsed, - val: m[0] - }); - }) - - /** - * Globstar: "**" - */ - - .capture('globstar', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\*{2}(?![*(])(?=[,)/]|$)/); - if (!m) return; - - var type = opts.noglobstar !== true ? 'globstar' : 'star'; - var node = pos({type: type, parsed: parsed}); - this.state.metachar = true; - - while (this.input.slice(0, 4) === '/**/') { - this.input = this.input.slice(3); - } - - node.isInside = { - brace: this.isInside('brace'), - paren: this.isInside('paren') - }; - - if (type === 'globstar') { - this.state.globstar = true; - node.val = '**'; - - } else { - this.state.star = true; - node.val = '*'; - } - - return node; - }) - - /** - * Star: "*" - */ - - .capture('star', function() { - var pos = this.position(); - var starRe = /^(?:\*(?![*(])|[*]{3,}(?!\()|[*]{2}(?![(/]|$)|\*(?=\*\())/; - var m = this.match(starRe); - if (!m) return; - - this.state.metachar = true; - this.state.star = true; - return pos({ - type: 'star', - val: m[0] - }); - }) - - /** - * Slash: "/" - */ - - .capture('slash', function() { - var pos = this.position(); - var m = this.match(/^\//); - if (!m) return; - - this.state.slashes++; - return pos({ - type: 'slash', - val: m[0] - }); - }) - - /** - * Backslash: "\\" - */ - - .capture('backslash', function() { - var pos = this.position(); - var m = this.match(/^\\(?![*+?(){}[\]'"])/); - if (!m) return; - - var val = m[0]; - - if (this.isInside('bracket')) { - val = '\\'; - } else if (val.length > 1) { - val = '\\\\'; - } - - return pos({ - type: 'backslash', - val: val - }); - }) - - /** - * Square: "[.]" - */ - - .capture('square', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^\[([^!^\\])\]/); - if (!m) return; - - return pos({ - type: 'square', - val: m[1] - }); - }) - - /** - * Brackets: "[...]" (basic, this can be overridden by other parsers) - */ - - .capture('bracket', function() { - var pos = this.position(); - var m = this.match(/^(?:\[([!^]?)([^\]]+|\]-)(\]|[^*+?]+)|\[)/); - if (!m) return; - - var val = m[0]; - var negated = m[1] ? '^' : ''; - var inner = (m[2] || '').replace(/\\\\+/, '\\\\'); - var close = m[3] || ''; - - if (m[2] && inner.length < m[2].length) { - val = val.replace(/\\\\+/, '\\\\'); - } - - var esc = this.input.slice(0, 2); - if (inner === '' && esc === '\\]') { - inner += esc; - this.consume(2); - - var str = this.input; - var idx = -1; - var ch; - - while ((ch = str[++idx])) { - this.consume(1); - if (ch === ']') { - close = ch; - break; - } - inner += ch; - } - } - - return pos({ - type: 'bracket', - val: val, - escaped: close !== ']', - negated: negated, - inner: inner, - close: close - }); - }) - - /** - * Text - */ - - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - return pos({ - type: 'text', - val: m[0] - }); - }); - - /** - * Allow custom parsers to be passed on options - */ - - if (options && typeof options.parsers === 'function') { - options.parsers(nanomatch.parser); - } -}; - -/** - * Advance to the next non-escaped character - */ - -function advanceTo(input, endChar) { - var ch = input.charAt(0); - var tok = { len: 1, val: '', esc: '' }; - var idx = 0; - - function advance() { - if (ch !== '\\') { - tok.esc += '\\' + ch; - tok.val += ch; - } - - ch = input.charAt(++idx); - tok.len++; - - if (ch === '\\') { - advance(); - advance(); - } - } - - while (ch && ch !== endChar) { - advance(); - } - return tok; -} - -/** - * Create text regex - */ - -function createTextRegex(pattern) { - if (cached) return cached; - var opts = {contains: true, strictClose: false}; - var not = regexNot.create(pattern, opts); - var re = toRegex('^(?:[*]\\((?=.)|' + not + ')', opts); - return (cached = re); -} - -/** - * Expose negation string - */ - -module.exports.not = NOT_REGEX; - - -/***/ }), -/* 688 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = new (__webpack_require__(689))(); - - -/***/ }), -/* 689 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * fragment-cache - * - * Copyright (c) 2016-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var MapCache = __webpack_require__(682); - -/** - * Create a new `FragmentCache` with an optional object to use for `caches`. - * - * ```js - * var fragment = new FragmentCache(); - * ``` - * @name FragmentCache - * @param {String} `cacheName` - * @return {Object} Returns the [map-cache][] instance. - * @api public - */ - -function FragmentCache(caches) { - this.caches = caches || {}; -} - -/** - * Prototype - */ - -FragmentCache.prototype = { - - /** - * Get cache `name` from the `fragment.caches` object. Creates a new - * `MapCache` if it doesn't already exist. - * - * ```js - * var cache = fragment.cache('files'); - * console.log(fragment.caches.hasOwnProperty('files')); - * //=> true - * ``` - * @name .cache - * @param {String} `cacheName` - * @return {Object} Returns the [map-cache][] instance. - * @api public - */ - - cache: function(cacheName) { - return this.caches[cacheName] || (this.caches[cacheName] = new MapCache()); - }, - - /** - * Set a value for property `key` on cache `name` - * - * ```js - * fragment.set('files', 'somefile.js', new File({path: 'somefile.js'})); - * ``` - * @name .set - * @param {String} `name` - * @param {String} `key` Property name to set - * @param {any} `val` The value of `key` - * @return {Object} The cache instance for chaining - * @api public - */ - - set: function(cacheName, key, val) { - var cache = this.cache(cacheName); - cache.set(key, val); - return cache; - }, - - /** - * Returns true if a non-undefined value is set for `key` on fragment cache `name`. - * - * ```js - * var cache = fragment.cache('files'); - * cache.set('somefile.js'); - * - * console.log(cache.has('somefile.js')); - * //=> true - * - * console.log(cache.has('some-other-file.js')); - * //=> false - * ``` - * @name .has - * @param {String} `name` Cache name - * @param {String} `key` Optionally specify a property to check for on cache `name` - * @return {Boolean} - * @api public - */ - - has: function(cacheName, key) { - return typeof this.get(cacheName, key) !== 'undefined'; - }, - - /** - * Get `name`, or if specified, the value of `key`. Invokes the [cache]() method, - * so that cache `name` will be created it doesn't already exist. If `key` is not passed, - * the entire cache (`name`) is returned. - * - * ```js - * var Vinyl = require('vinyl'); - * var cache = fragment.cache('files'); - * cache.set('somefile.js', new Vinyl({path: 'somefile.js'})); - * console.log(cache.get('somefile.js')); - * //=> - * ``` - * @name .get - * @param {String} `name` - * @return {Object} Returns cache `name`, or the value of `key` if specified - * @api public - */ - - get: function(name, key) { - var cache = this.cache(name); - if (typeof key === 'string') { - return cache.get(key); - } - return cache; - } -}; - -/** - * Expose `FragmentCache` - */ - -exports = module.exports = FragmentCache; - - -/***/ }), -/* 690 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = module.exports; -var path = __webpack_require__(4); - -/** - * Module dependencies - */ - -var isWindows = __webpack_require__(691)(); -var Snapdragon = __webpack_require__(618); -utils.define = __webpack_require__(692); -utils.diff = __webpack_require__(693); -utils.extend = __webpack_require__(595); -utils.pick = __webpack_require__(694); -utils.typeOf = __webpack_require__(592); -utils.unique = __webpack_require__(600); - -/** - * Returns true if the given value is effectively an empty string - */ - -utils.isEmptyString = function(val) { - return String(val) === '' || String(val) === './'; -}; - -/** - * Returns true if the platform is windows, or `path.sep` is `\\`. - * This is defined as a function to allow `path.sep` to be set in unit tests, - * or by the user, if there is a reason to do so. - * @return {Boolean} - */ - -utils.isWindows = function() { - return path.sep === '\\' || isWindows === true; -}; - -/** - * Return the last element from an array - */ - -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - -/** - * Get the `Snapdragon` instance to use - */ - -utils.instantiate = function(ast, options) { - var snapdragon; - // if an instance was created by `.parse`, use that instance - if (utils.typeOf(ast) === 'object' && ast.snapdragon) { - snapdragon = ast.snapdragon; - // if the user supplies an instance on options, use that instance - } else if (utils.typeOf(options) === 'object' && options.snapdragon) { - snapdragon = options.snapdragon; - // create a new instance - } else { - snapdragon = new Snapdragon(options); - } - - utils.define(snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.call(this, str, options); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strictErrors !== true) { - var open = last.nodes[0]; - var inner = last.nodes[1]; - if (last.type === 'bracket') { - if (inner.val.charAt(0) === '[') { - inner.val = '\\' + inner.val; - } - - } else { - open.val = '\\' + open.val; - var sibling = open.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - } - - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); - - return snapdragon; -}; - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -utils.createKey = function(pattern, options) { - if (typeof options === 'undefined') { - return pattern; - } - var key = pattern; - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); - } - } - return key; -}; - -/** - * Cast `val` to an array - * @return {Array} - */ - -utils.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isString = function(val) { - return typeof val === 'string'; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isRegex = function(val) { - return utils.typeOf(val) === 'regexp'; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isObject = function(val) { - return utils.typeOf(val) === 'object'; -}; - -/** - * Escape regex characters in the given string - */ - -utils.escapeRegex = function(str) { - return str.replace(/[-[\]{}()^$|*+?.\\/\s]/g, '\\$&'); -}; - -/** - * Combines duplicate characters in the provided `input` string. - * @param {String} `input` - * @returns {String} - */ - -utils.combineDupes = function(input, patterns) { - patterns = utils.arrayify(patterns).join('|').split('|'); - patterns = patterns.map(function(s) { - return s.replace(/\\?([+*\\/])/g, '\\$1'); - }); - var substr = patterns.join('|'); - var regex = new RegExp('(' + substr + ')(?=\\1)', 'g'); - return input.replace(regex, ''); -}; - -/** - * Returns true if the given `str` has special characters - */ - -utils.hasSpecialChars = function(str) { - return /(?:(?:(^|\/)[!.])|[*?+()|[\]{}]|[+@]\()/.test(str); -}; - -/** - * Normalize slashes in the given filepath. - * - * @param {String} `filepath` - * @return {String} - */ - -utils.toPosixPath = function(str) { - return str.replace(/\\+/g, '/'); -}; - -/** - * Strip backslashes before special characters in a string. - * - * @param {String} `str` - * @return {String} - */ - -utils.unescape = function(str) { - return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); -}; - -/** - * Strip the drive letter from a windows filepath - * @param {String} `fp` - * @return {String} - */ - -utils.stripDrive = function(fp) { - return utils.isWindows() ? fp.replace(/^[a-z]:[\\/]+?/i, '/') : fp; -}; - -/** - * Strip the prefix from a filepath - * @param {String} `fp` - * @return {String} - */ - -utils.stripPrefix = function(str) { - if (str.charAt(0) === '.' && (str.charAt(1) === '/' || str.charAt(1) === '\\')) { - return str.slice(2); - } - return str; -}; - -/** - * Returns true if `str` is a common character that doesn't need - * to be processed to be used for matching. - * @param {String} `str` - * @return {Boolean} - */ - -utils.isSimpleChar = function(str) { - return str.trim() === '' || str === '.'; -}; - -/** - * Returns true if the given str is an escaped or - * unescaped path character - */ - -utils.isSlash = function(str) { - return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; -}; - -/** - * Returns a function that returns true if the given - * pattern matches or contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.matchPath = function(pattern, options) { - return (options && options.contains) - ? utils.containsPattern(pattern, options) - : utils.equalsPattern(pattern, options); -}; - -/** - * Returns true if the given (original) filepath or unixified path are equal - * to the given pattern. - */ - -utils._equals = function(filepath, unixPath, pattern) { - return pattern === filepath || pattern === unixPath; -}; - -/** - * Returns true if the given (original) filepath or unixified path contain - * the given pattern. - */ - -utils._contains = function(filepath, unixPath, pattern) { - return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; -}; - -/** - * Returns a function that returns true if the given - * pattern is the same as a given `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.equalsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function fn(filepath) { - var equal = utils._equals(filepath, unixify(filepath), pattern); - if (equal === true || options.nocase !== true) { - return equal; - } - var lower = filepath.toLowerCase(); - return utils._equals(lower, unixify(lower), pattern); - }; -}; - -/** - * Returns a function that returns true if the given - * pattern contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.containsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function(filepath) { - var contains = utils._contains(filepath, unixify(filepath), pattern); - if (contains === true || options.nocase !== true) { - return contains; - } - var lower = filepath.toLowerCase(); - return utils._contains(lower, unixify(lower), pattern); - }; -}; - -/** - * Returns a function that returns true if the given - * regex matches the `filename` of a file path. - * - * @param {RegExp} `re` Matching regex - * @return {Function} - */ - -utils.matchBasename = function(re) { - return function(filepath) { - return re.test(filepath) || re.test(path.basename(filepath)); - }; -}; - -/** - * Returns the given value unchanced. - * @return {any} - */ - -utils.identity = function(val) { - return val; -}; - -/** - * Determines the filepath to return based on the provided options. - * @return {any} - */ - -utils.value = function(str, unixify, options) { - if (options && options.unixify === false) { - return str; - } - if (options && typeof options.unixify === 'function') { - return options.unixify(str); - } - return unixify(str); -}; - -/** - * Returns a function that normalizes slashes in a string to forward - * slashes, strips `./` from beginning of paths, and optionally unescapes - * special characters. - * @return {Function} - */ - -utils.unixify = function(options) { - var opts = options || {}; - return function(filepath) { - if (opts.stripPrefix !== false) { - filepath = utils.stripPrefix(filepath); - } - if (opts.unescape === true) { - filepath = utils.unescape(filepath); - } - if (opts.unixify === true || utils.isWindows()) { - filepath = utils.toPosixPath(filepath); - } - return filepath; - }; -}; - - -/***/ }), -/* 691 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! - * is-windows - * - * Copyright © 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ - -(function(factory) { - if (exports && typeof exports === 'object' && typeof module !== 'undefined') { - module.exports = factory(); - } else if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else {} -})(function() { - 'use strict'; - return function isWindows() { - return process && (process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE)); - }; -}); - - -/***/ }), -/* 692 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isobject = __webpack_require__(590); -var isDescriptor = __webpack_require__(591); -var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) - ? Reflect.defineProperty - : Object.defineProperty; - -module.exports = function defineProperty(obj, key, val) { - if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { - throw new TypeError('expected an object, function, or array'); - } - - if (typeof key !== 'string') { - throw new TypeError('expected "key" to be a string'); - } - - if (isDescriptor(val)) { - define(obj, key, val); - return obj; - } - - define(obj, key, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); - - return obj; -}; - - -/***/ }), -/* 693 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * arr-diff - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function diff(arr/*, arrays*/) { - var len = arguments.length; - var idx = 0; - while (++idx < len) { - arr = diffArray(arr, arguments[idx]); - } - return arr; -}; - -function diffArray(one, two) { - if (!Array.isArray(two)) { - return one.slice(); - } - - var tlen = two.length - var olen = one.length; - var idx = -1; - var arr = []; - - while (++idx < olen) { - var ele = one[idx]; - - var hasEle = false; - for (var i = 0; i < tlen; i++) { - var val = two[i]; - - if (ele === val) { - hasEle = true; - break; - } - } - - if (hasEle === false) { - arr.push(ele); - } - } - return arr; -} - - -/***/ }), -/* 694 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * object.pick - * - * Copyright (c) 2014-2015 Jon Schlinkert, contributors. - * Licensed under the MIT License - */ - - - -var isObject = __webpack_require__(590); - -module.exports = function pick(obj, keys) { - if (!isObject(obj) && typeof obj !== 'function') { - return {}; - } - - var res = {}; - if (typeof keys === 'string') { - if (keys in obj) { - res[keys] = obj[keys]; - } - return res; - } - - var len = keys.length; - var idx = -1; - - while (++idx < len) { - var key = keys[idx]; - if (key in obj) { - res[key] = obj[key]; - } - } - return res; -}; - - -/***/ }), -/* 695 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var extend = __webpack_require__(696); -var unique = __webpack_require__(600); -var toRegex = __webpack_require__(582); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(697); -var parsers = __webpack_require__(709); -var Extglob = __webpack_require__(712); -var utils = __webpack_require__(711); -var MAX_LENGTH = 1024 * 64; - -/** - * Convert the given `extglob` pattern into a regex-compatible string. Returns - * an object with the compiled result and the parsed AST. - * - * ```js - * var extglob = require('extglob'); - * console.log(extglob('*.!(*a)')); - * //=> '(?!\\.)[^/]*?\\.(?!(?!\\.)[^/]*?a\\b).*?' - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {String} - * @api public - */ - -function extglob(pattern, options) { - return extglob.create(pattern, options).output; -} - -/** - * Takes an array of strings and an extglob pattern and returns a new - * array that contains only the strings that match the pattern. - * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.match(['a.a', 'a.b', 'a.c'], '*.!(*a)')); - * //=> ['a.b', 'a.c'] - * ``` - * @param {Array} `list` Array of strings to match - * @param {String} `pattern` Extglob pattern - * @param {Object} `options` - * @return {Array} Returns an array of matches - * @api public - */ - -extglob.match = function(list, pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - list = utils.arrayify(list); - var isMatch = extglob.matcher(pattern, options); - var len = list.length; - var idx = -1; - var matches = []; - - while (++idx < len) { - var ele = list[idx]; - - if (isMatch(ele)) { - matches.push(ele); - } - } - - // if no options were passed, uniquify results and return - if (typeof options === 'undefined') { - return unique(matches); - } - - if (matches.length === 0) { - if (options.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - if (options.nonull === true || options.nullglob === true) { - return [pattern.split('\\').join('')]; - } - } - - return options.nodupes !== false ? unique(matches) : matches; -}; - -/** - * Returns true if the specified `string` matches the given - * extglob `pattern`. - * - * ```js - * var extglob = require('extglob'); - * - * console.log(extglob.isMatch('a.a', '*.!(*a)')); - * //=> false - * console.log(extglob.isMatch('a.b', '*.!(*a)')); - * //=> true - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Extglob pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ - -extglob.isMatch = function(str, pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - if (pattern === str) { - return true; - } - - if (pattern === '' || pattern === ' ' || pattern === '.') { - return pattern === str; - } - - var isMatch = utils.memoize('isMatch', pattern, options, extglob.matcher); - return isMatch(str); -}; - -/** - * Returns true if the given `string` contains the given pattern. Similar to `.isMatch` but - * the pattern can match any part of the string. - * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(extglob.contains('aa/bb/cc', '*d')); - * //=> false - * ``` - * @param {String} `str` The string to match. - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` - * @return {Boolean} Returns true if the patter matches any part of `str`. - * @api public - */ - -extglob.contains = function(str, pattern, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } - - if (pattern === '' || pattern === ' ' || pattern === '.') { - return pattern === str; - } - - var opts = extend({}, options, {contains: true}); - opts.strictClose = false; - opts.strictOpen = false; - return extglob.isMatch(str, pattern, opts); -}; - -/** - * Takes an extglob pattern and returns a matcher function. The returned - * function takes the string to match as its only argument. - * - * ```js - * var extglob = require('extglob'); - * var isMatch = extglob.matcher('*.!(*a)'); - * - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.b')); - * //=> true - * ``` - * @param {String} `pattern` Extglob pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ - -extglob.matcher = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - function matcher() { - var re = extglob.makeRe(pattern, options); - return function(str) { - return re.test(str); - }; - } - - return utils.memoize('matcher', pattern, options, matcher); -}; - -/** - * Convert the given `extglob` pattern into a regex-compatible string. Returns - * an object with the compiled result and the parsed AST. - * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.create('*.!(*a)').output); - * //=> '(?!\\.)[^/]*?\\.(?!(?!\\.)[^/]*?a\\b).*?' - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {String} - * @api public - */ - -extglob.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - function create() { - var ext = new Extglob(options); - var ast = ext.parse(pattern, options); - return ext.compile(ast, options); - } - - return utils.memoize('create', pattern, options, create); -}; - -/** - * Returns an array of matches captured by `pattern` in `string`, or `null` - * if the pattern did not match. - * - * ```js - * var extglob = require('extglob'); - * extglob.capture(pattern, string[, options]); - * - * console.log(extglob.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(extglob.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `pattern` Glob pattern to use for matching. - * @param {String} `string` String to match - * @param {Object} `options` See available [options](#options) for changing how matches are performed - * @return {Boolean} Returns an array of captures if the string matches the glob pattern, otherwise `null`. - * @api public - */ - -extglob.capture = function(pattern, str, options) { - var re = extglob.makeRe(pattern, extend({capture: true}, options)); - - function match() { - return function(string) { - var match = re.exec(string); - if (!match) { - return null; - } - - return match.slice(1); - }; - } - - var capture = utils.memoize('capture', pattern, options, match); - return capture(str); -}; - -/** - * Create a regular expression from the given `pattern` and `options`. - * - * ```js - * var extglob = require('extglob'); - * var re = extglob.makeRe('*.!(*a)'); - * console.log(re); - * //=> /^[^\/]*?\.(?![^\/]*?a)[^\/]*?$/ - * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -extglob.makeRe = function(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } - - function makeRe() { - var opts = extend({strictErrors: false}, options); - if (opts.strictErrors === true) opts.strict = true; - var res = extglob.create(pattern, opts); - return toRegex(res.output, opts); - } - - var regex = utils.memoize('makeRe', pattern, options, makeRe); - if (regex.source.length > MAX_LENGTH) { - throw new SyntaxError('potentially malicious regex detected'); - } - - return regex; -}; - -/** - * Cache - */ - -extglob.cache = utils.cache; -extglob.clearCache = function() { - extglob.cache.__data__ = {}; -}; - -/** - * Expose `Extglob` constructor, parsers and compilers - */ - -extglob.Extglob = Extglob; -extglob.compilers = compilers; -extglob.parsers = parsers; - -/** - * Expose `extglob` - * @type {Function} - */ - -module.exports = extglob; - - -/***/ }), -/* 696 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(602); - -module.exports = function extend(o/*, objects*/) { - if (!isObject(o)) { o = {}; } - - var len = arguments.length; - for (var i = 1; i < len; i++) { - var obj = arguments[i]; - - if (isObject(obj)) { - assign(o, obj); - } - } - return o; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - - -/***/ }), -/* 697 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var brackets = __webpack_require__(698); - -/** - * Extglob compilers - */ - -module.exports = function(extglob) { - function star() { - if (typeof extglob.options.star === 'function') { - return extglob.options.star.apply(this, arguments); - } - if (typeof extglob.options.star === 'string') { - return extglob.options.star; - } - return '.*?'; - } - - /** - * Use `expand-brackets` compilers - */ - - extglob.use(brackets.compilers); - extglob.compiler - - /** - * Escaped: "\\*" - */ - - .set('escape', function(node) { - return this.emit(node.val, node); - }) - - /** - * Dot: "." - */ - - .set('dot', function(node) { - return this.emit('\\' + node.val, node); - }) - - /** - * Question mark: "?" - */ - - .set('qmark', function(node) { - var val = '[^\\\\/.]'; - var prev = this.prev(); - - if (node.parsed.slice(-1) === '(') { - var ch = node.rest.charAt(0); - if (ch !== '!' && ch !== '=' && ch !== ':') { - return this.emit(val, node); - } - return this.emit(node.val, node); - } - - if (prev.type === 'text' && prev.val) { - return this.emit(val, node); - } - - if (node.val.length > 1) { - val += '{' + node.val.length + '}'; - } - return this.emit(val, node); - }) - - /** - * Plus: "+" - */ - - .set('plus', function(node) { - var prev = node.parsed.slice(-1); - if (prev === ']' || prev === ')') { - return this.emit(node.val, node); - } - var ch = this.output.slice(-1); - if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) { - return this.emit('\\+', node); - } - if (/\w/.test(ch) && !node.inside) { - return this.emit('+\\+?', node); - } - return this.emit('+', node); - }) - - /** - * Star: "*" - */ - - .set('star', function(node) { - var prev = this.prev(); - var prefix = prev.type !== 'text' && prev.type !== 'escape' - ? '(?!\\.)' - : ''; - - return this.emit(prefix + star.call(this, node), node); - }) - - /** - * Parens - */ - - .set('paren', function(node) { - return this.mapVisit(node.nodes); - }) - .set('paren.open', function(node) { - var capture = this.options.capture ? '(' : ''; - - switch (node.parent.prefix) { - case '!': - case '^': - return this.emit(capture + '(?:(?!(?:', node); - case '*': - case '+': - case '?': - case '@': - return this.emit(capture + '(?:', node); - default: { - var val = node.val; - if (this.options.bash === true) { - val = '\\' + val; - } else if (!this.options.capture && val === '(' && node.parent.rest[0] !== '?') { - val += '?:'; - } - - return this.emit(val, node); - } - } - }) - .set('paren.close', function(node) { - var capture = this.options.capture ? ')' : ''; - - switch (node.prefix) { - case '!': - case '^': - var prefix = /^(\)|$)/.test(node.rest) ? '$' : ''; - var str = star.call(this, node); - - // if the extglob has a slash explicitly defined, we know the user wants - // to match slashes, so we need to ensure the "star" regex allows for it - if (node.parent.hasSlash && !this.options.star && this.options.slash !== false) { - str = '.*?'; - } - - return this.emit(prefix + ('))' + str + ')') + capture, node); - case '*': - case '+': - case '?': - return this.emit(')' + node.prefix + capture, node); - case '@': - return this.emit(')' + capture, node); - default: { - var val = (this.options.bash === true ? '\\' : '') + ')'; - return this.emit(val, node); - } - } - }) - - /** - * Text - */ - - .set('text', function(node) { - var val = node.val.replace(/[\[\]]/g, '\\$&'); - return this.emit(val, node); - }); -}; - - -/***/ }), -/* 698 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(699); -var parsers = __webpack_require__(701); - -/** - * Module dependencies - */ - -var debug = __webpack_require__(703)('expand-brackets'); -var extend = __webpack_require__(708); -var Snapdragon = __webpack_require__(618); -var toRegex = __webpack_require__(582); - -/** - * Parses the given POSIX character class `pattern` and returns a - * string that can be used for creating regular expressions for matching. - * - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} - * @api public - */ - -function brackets(pattern, options) { - debug('initializing from <%s>', __filename); - var res = brackets.create(pattern, options); - return res.output; -} - -/** - * Takes an array of strings and a POSIX character class pattern, and returns a new - * array with only the strings that matched the pattern. - * - * ```js - * var brackets = require('expand-brackets'); - * console.log(brackets.match(['1', 'a', 'ab'], '[[:alpha:]]')); - * //=> ['a'] - * - * console.log(brackets.match(['1', 'a', 'ab'], '[[:alpha:]]+')); - * //=> ['a', 'ab'] - * ``` - * @param {Array} `arr` Array of strings to match - * @param {String} `pattern` POSIX character class pattern(s) - * @param {Object} `options` - * @return {Array} - * @api public - */ - -brackets.match = function(arr, pattern, options) { - arr = [].concat(arr); - var opts = extend({}, options); - var isMatch = brackets.matcher(pattern, opts); - var len = arr.length; - var idx = -1; - var res = []; - - while (++idx < len) { - var ele = arr[idx]; - if (isMatch(ele)) { - res.push(ele); - } - } - - if (res.length === 0) { - if (opts.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - - if (opts.nonull === true || opts.nullglob === true) { - return [pattern.split('\\').join('')]; - } - } - return res; -}; - -/** - * Returns true if the specified `string` matches the given - * brackets `pattern`. - * - * ```js - * var brackets = require('expand-brackets'); - * - * console.log(brackets.isMatch('a.a', '[[:alpha:]].[[:alpha:]]')); - * //=> true - * console.log(brackets.isMatch('1.2', '[[:alpha:]].[[:alpha:]]')); - * //=> false - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Poxis pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ - -brackets.isMatch = function(str, pattern, options) { - return brackets.matcher(pattern, options)(str); -}; - -/** - * Takes a POSIX character class pattern and returns a matcher function. The returned - * function takes the string to match as its only argument. - * - * ```js - * var brackets = require('expand-brackets'); - * var isMatch = brackets.matcher('[[:lower:]].[[:upper:]]'); - * - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.A')); - * //=> true - * ``` - * @param {String} `pattern` Poxis pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ - -brackets.matcher = function(pattern, options) { - var re = brackets.makeRe(pattern, options); - return function(str) { - return re.test(str); - }; -}; - -/** - * Create a regular expression from the given `pattern`. - * - * ```js - * var brackets = require('expand-brackets'); - * var re = brackets.makeRe('[[:alpha:]]'); - * console.log(re); - * //=> /^(?:[a-zA-Z])$/ - * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} - * @api public - */ - -brackets.makeRe = function(pattern, options) { - var res = brackets.create(pattern, options); - var opts = extend({strictErrors: false}, options); - return toRegex(res.output, opts); -}; - -/** - * Parses the given POSIX character class `pattern` and returns an object - * with the compiled `output` and optional source `map`. - * - * ```js - * var brackets = require('expand-brackets'); - * console.log(brackets('[[:alpha:]]')); - * // { options: { source: 'string' }, - * // input: '[[:alpha:]]', - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // not: [Function], - * // escape: [Function], - * // text: [Function], - * // posix: [Function], - * // bracket: [Function], - * // 'bracket.open': [Function], - * // 'bracket.inner': [Function], - * // 'bracket.literal': [Function], - * // 'bracket.close': [Function] }, - * // output: '[a-zA-Z]', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: [ [Object], [Object], [Object] ] }, - * // parsingErrors: [] } - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} - * @api public - */ - -brackets.create = function(pattern, options) { - var snapdragon = (options && options.snapdragon) || new Snapdragon(options); - compilers(snapdragon); - parsers(snapdragon); - - var ast = snapdragon.parse(pattern, options); - ast.input = pattern; - var res = snapdragon.compile(ast, options); - res.input = pattern; - return res; -}; - -/** - * Expose `brackets` constructor, parsers and compilers - */ - -brackets.compilers = compilers; -brackets.parsers = parsers; - -/** - * Expose `brackets` - * @type {Function} - */ - -module.exports = brackets; - - -/***/ }), -/* 699 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var posix = __webpack_require__(700); - -module.exports = function(brackets) { - brackets.compiler - - /** - * Escaped characters - */ - - .set('escape', function(node) { - return this.emit('\\' + node.val.replace(/^\\/, ''), node); - }) - - /** - * Text - */ - - .set('text', function(node) { - return this.emit(node.val.replace(/([{}])/g, '\\$1'), node); - }) - - /** - * POSIX character classes - */ - - .set('posix', function(node) { - if (node.val === '[::]') { - return this.emit('\\[::\\]', node); - } - - var val = posix[node.inner]; - if (typeof val === 'undefined') { - val = '[' + node.inner + ']'; - } - return this.emit(val, node); - }) - - /** - * Non-posix brackets - */ - - .set('bracket', function(node) { - return this.mapVisit(node.nodes); - }) - .set('bracket.open', function(node) { - return this.emit(node.val, node); - }) - .set('bracket.inner', function(node) { - var inner = node.val; - - if (inner === '[' || inner === ']') { - return this.emit('\\' + node.val, node); - } - if (inner === '^]') { - return this.emit('^\\]', node); - } - if (inner === '^') { - return this.emit('^', node); - } - - if (/-/.test(inner) && !/(\d-\d|\w-\w)/.test(inner)) { - inner = inner.split('-').join('\\-'); - } - - var isNegated = inner.charAt(0) === '^'; - // add slashes to negated brackets, per spec - if (isNegated && inner.indexOf('/') === -1) { - inner += '/'; - } - if (isNegated && inner.indexOf('.') === -1) { - inner += '.'; - } - - // don't unescape `0` (octal literal) - inner = inner.replace(/\\([1-9])/g, '$1'); - return this.emit(inner, node); - }) - .set('bracket.close', function(node) { - var val = node.val.replace(/^\\/, ''); - if (node.parent.escaped === true) { - return this.emit('\\' + val, node); - } - return this.emit(val, node); - }); -}; - - -/***/ }), -/* 700 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * POSIX character classes - */ - -module.exports = { - alnum: 'a-zA-Z0-9', - alpha: 'a-zA-Z', - ascii: '\\x00-\\x7F', - blank: ' \\t', - cntrl: '\\x00-\\x1F\\x7F', - digit: '0-9', - graph: '\\x21-\\x7E', - lower: 'a-z', - print: '\\x20-\\x7E ', - punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', - space: ' \\t\\r\\n\\v\\f', - upper: 'A-Z', - word: 'A-Za-z0-9_', - xdigit: 'A-Fa-f0-9' -}; - - -/***/ }), -/* 701 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = __webpack_require__(702); -var define = __webpack_require__(645); - -/** - * Text regex - */ - -var TEXT_REGEX = '(\\[(?=.*\\])|\\])+'; -var not = utils.createRegex(TEXT_REGEX); - -/** - * Brackets parsers - */ - -function parsers(brackets) { - brackets.state = brackets.state || {}; - brackets.parser.sets.bracket = brackets.parser.sets.bracket || []; - brackets.parser - - .capture('escape', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^\\(.)/); - if (!m) return; - - return pos({ - type: 'escape', - val: m[0] - }); - }) - - /** - * Text parser - */ - - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - return pos({ - type: 'text', - val: m[0] - }); - }) - - /** - * POSIX character classes: "[[:alpha:][:digits:]]" - */ - - .capture('posix', function() { - var pos = this.position(); - var m = this.match(/^\[:(.*?):\](?=.*\])/); - if (!m) return; - - var inside = this.isInside('bracket'); - if (inside) { - brackets.posix++; - } - - return pos({ - type: 'posix', - insideBracket: inside, - inner: m[1], - val: m[0] - }); - }) - - /** - * Bracket (noop) - */ - - .capture('bracket', function() {}) - - /** - * Open: '[' - */ - - .capture('bracket.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\[(?=.*\])/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { - last.val = last.val.slice(0, last.val.length - 1); - return pos({ - type: 'escape', - val: m[0] - }); - } - - var open = pos({ - type: 'bracket.open', - val: m[0] - }); - - if (last.type === 'bracket.open' || this.isInside('bracket')) { - open.val = '\\' + open.val; - open.type = 'bracket.inner'; - open.escaped = true; - return open; - } - - var node = pos({ - type: 'bracket', - nodes: [open] - }); - - define(node, 'parent', prev); - define(open, 'parent', node); - this.push('bracket', node); - prev.nodes.push(node); - }) - - /** - * Bracket text - */ - - .capture('bracket.inner', function() { - if (!this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - var next = this.input.charAt(0); - var val = m[0]; - - var node = pos({ - type: 'bracket.inner', - val: val - }); - - if (val === '\\\\') { - return node; - } - - var first = val.charAt(0); - var last = val.slice(-1); - - if (first === '!') { - val = '^' + val.slice(1); - } - - if (last === '\\' || (val === '^' && next === ']')) { - val += this.input[0]; - this.consume(1); - } - - node.val = val; - return node; - }) - - /** - * Close: ']' - */ - - .capture('bracket.close', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\]/); - if (!m) return; - - var prev = this.prev(); - var last = utils.last(prev.nodes); - - if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { - last.val = last.val.slice(0, last.val.length - 1); - - return pos({ - type: 'escape', - val: m[0] - }); - } - - var node = pos({ - type: 'bracket.close', - rest: this.input, - val: m[0] - }); - - if (last.type === 'bracket.open') { - node.type = 'bracket.inner'; - node.escaped = true; - return node; - } - - var bracket = this.pop('bracket'); - if (!this.isType(bracket, 'bracket')) { - if (this.options.strict) { - throw new Error('missing opening "["'); - } - node.type = 'bracket.inner'; - node.escaped = true; - return node; - } - - bracket.nodes.push(node); - define(node, 'parent', bracket); - }); -} - -/** - * Brackets parsers - */ - -module.exports = parsers; - -/** - * Expose text regex - */ - -module.exports.TEXT_REGEX = TEXT_REGEX; - - -/***/ }), -/* 702 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var toRegex = __webpack_require__(582); -var regexNot = __webpack_require__(599); -var cached; - -/** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} - */ - -exports.last = function(arr) { - return arr[arr.length - 1]; -}; - -/** - * Create and cache regex to use for text nodes - */ - -exports.createRegex = function(pattern, include) { - if (cached) return cached; - var opts = {contains: true, strictClose: false}; - var not = regexNot.create(pattern, opts); - var re; - - if (typeof include === 'string') { - re = toRegex('^(?:' + include + '|' + not + ')', opts); - } else { - re = toRegex(not, opts); - } - - return (cached = re); -}; - - -/***/ }), -/* 703 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. - */ - -if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(704); -} else { - module.exports = __webpack_require__(707); -} - - -/***/ }), -/* 704 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(705); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; - } - - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} - - -/***/ }), -/* 705 */ -/***/ (function(module, exports, __webpack_require__) { - - -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = __webpack_require__(706); - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; - -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ - -exports.formatters = {}; - -/** - * Previous log timestamp. - */ - -var prevTime; - -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ - -function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer - } - - return exports.colors[Math.abs(hash) % exports.colors.length]; -} - -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); - - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); - - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } - - return debug; -} - -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - -function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } -} - -/** - * Disable debug output. - * - * @api public - */ - -function disable() { - exports.enable(''); -} - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - - -/***/ }), -/* 706 */ -/***/ (function(module, exports) { - -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; -} - - -/***/ }), -/* 707 */ -/***/ (function(module, exports, __webpack_require__) { - -/** - * Module dependencies. - */ - -var tty = __webpack_require__(122); -var util = __webpack_require__(112); - -/** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = __webpack_require__(705); -exports.init = init; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; - -/** - * Colors. - */ - -exports.colors = [6, 2, 3, 4, 5, 1]; - -/** - * Build up the default `inspectOpts` object from the environment variables. - * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js - */ - -exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); -}).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); - - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); - - obj[prop] = val; - return obj; -}, {}); - -/** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ - -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; - -if (1 !== fd && 2 !== fd) { - util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() -} - -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); - -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ - -function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); -} - -/** - * Map %o to `util.inspect()`, all on a single line. - */ - -exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); -}; - -/** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ - -exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts); -}; - -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ - -function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; - - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; - - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } -} - -/** - * Invokes `util.format()` with the specified arguments and writes to `stream`. - */ - -function log() { - return stream.write(util.format.apply(util, arguments) + '\n'); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - return process.env.DEBUG; -} - -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ - -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - case 'FILE': - var fs = __webpack_require__(134); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = __webpack_require__(659); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); - - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; - - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; -} - -/** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ - -function init (debug) { - debug.inspectOpts = {}; - - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } -} - -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - -exports.enable(load()); - - -/***/ }), -/* 708 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isObject = __webpack_require__(602); - -module.exports = function extend(o/*, objects*/) { - if (!isObject(o)) { o = {}; } - - var len = arguments.length; - for (var i = 1; i < len; i++) { - var obj = arguments[i]; - - if (isObject(obj)) { - assign(o, obj); - } - } - return o; -}; - -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} - -/** - * Returns true if the given `key` is an own property of `obj`. - */ - -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - - -/***/ }), -/* 709 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var brackets = __webpack_require__(698); -var define = __webpack_require__(710); -var utils = __webpack_require__(711); - -/** - * Characters to use in text regex (we want to "not" match - * characters that are matched by other parsers) - */ - -var TEXT_REGEX = '([!@*?+]?\\(|\\)|[*?.+\\\\]|\\[:?(?=.*\\])|:?\\])+'; -var not = utils.createRegex(TEXT_REGEX); - -/** - * Extglob parsers - */ - -function parsers(extglob) { - extglob.state = extglob.state || {}; - - /** - * Use `expand-brackets` parsers - */ - - extglob.use(brackets.parsers); - extglob.parser.sets.paren = extglob.parser.sets.paren || []; - extglob.parser - - /** - * Extglob open: "*(" - */ - - .capture('paren.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^([!@*?+])?\(/); - if (!m) return; - - var prev = this.prev(); - var prefix = m[1]; - var val = m[0]; - - var open = pos({ - type: 'paren.open', - parsed: parsed, - val: val - }); - - var node = pos({ - type: 'paren', - prefix: prefix, - nodes: [open] - }); - - // if nested negation extglobs, just cancel them out to simplify - if (prefix === '!' && prev.type === 'paren' && prev.prefix === '!') { - prev.prefix = '@'; - node.prefix = '@'; - } - - define(node, 'rest', this.input); - define(node, 'parsed', parsed); - define(node, 'parent', prev); - define(open, 'parent', node); - - this.push('paren', node); - prev.nodes.push(node); - }) - - /** - * Extglob close: ")" - */ - - .capture('paren.close', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\)/); - if (!m) return; - - var parent = this.pop('paren'); - var node = pos({ - type: 'paren.close', - rest: this.input, - parsed: parsed, - val: m[0] - }); - - if (!this.isType(parent, 'paren')) { - if (this.options.strict) { - throw new Error('missing opening paren: "("'); - } - node.escaped = true; - return node; - } - - node.prefix = parent.prefix; - parent.nodes.push(node); - define(node, 'parent', parent); - }) - - /** - * Escape: "\\." - */ - - .capture('escape', function() { - var pos = this.position(); - var m = this.match(/^\\(.)/); - if (!m) return; - - return pos({ - type: 'escape', - val: m[0], - ch: m[1] - }); - }) - - /** - * Question marks: "?" - */ - - .capture('qmark', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\?+(?!\()/); - if (!m) return; - extglob.state.metachar = true; - return pos({ - type: 'qmark', - rest: this.input, - parsed: parsed, - val: m[0] - }); - }) - - /** - * Character parsers - */ - - .capture('star', /^\*(?!\()/) - .capture('plus', /^\+(?!\()/) - .capture('dot', /^\./) - .capture('text', not); -}; - -/** - * Expose text regex string - */ - -module.exports.TEXT_REGEX = TEXT_REGEX; - -/** - * Extglob parsers - */ - -module.exports = parsers; - - -/***/ }), -/* 710 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isDescriptor = __webpack_require__(591); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; - - -/***/ }), -/* 711 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var regex = __webpack_require__(599); -var Cache = __webpack_require__(689); - -/** - * Utils - */ - -var utils = module.exports; -var cache = utils.cache = new Cache(); - -/** - * Cast `val` to an array - * @return {Array} - */ - -utils.arrayify = function(val) { - if (!Array.isArray(val)) { - return [val]; - } - return val; -}; - -/** - * Memoize a generated regex or function - */ - -utils.memoize = function(type, pattern, options, fn) { - var key = utils.createKey(type + pattern, options); - - if (cache.has(type, key)) { - return cache.get(type, key); - } - - var val = fn(pattern, options); - if (options && options.cache === false) { - return val; - } - - cache.set(type, key, val); - return val; -}; - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -utils.createKey = function(pattern, options) { - var key = pattern; - if (typeof options === 'undefined') { - return key; - } - for (var prop in options) { - key += ';' + prop + '=' + String(options[prop]); - } - return key; -}; - -/** - * Create the regex to use for matching text - */ - -utils.createRegex = function(str) { - var opts = {contains: true, strictClose: false}; - return regex(str, opts); -}; - - -/***/ }), -/* 712 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Module dependencies - */ - -var Snapdragon = __webpack_require__(618); -var define = __webpack_require__(710); -var extend = __webpack_require__(696); - -/** - * Local dependencies - */ - -var compilers = __webpack_require__(697); -var parsers = __webpack_require__(709); - -/** - * Customize Snapdragon parser and renderer - */ - -function Extglob(options) { - this.options = extend({source: 'extglob'}, options); - this.snapdragon = this.options.snapdragon || new Snapdragon(this.options); - this.snapdragon.patterns = this.snapdragon.patterns || {}; - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; - - compilers(this.snapdragon); - parsers(this.snapdragon); - - /** - * Override Snapdragon `.parse` method - */ - - define(this.snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strict !== true) { - var node = last.nodes[0]; - node.val = '\\' + node.val; - var sibling = node.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - - // add non-enumerable parser reference - define(parsed, 'parser', this.parser); - return parsed; - }); - - /** - * Decorate `.parse` method - */ - - define(this, 'parse', function(ast, options) { - return this.snapdragon.parse.apply(this.snapdragon, arguments); - }); - - /** - * Decorate `.compile` method - */ - - define(this, 'compile', function(ast, options) { - return this.snapdragon.compile.apply(this.snapdragon, arguments); - }); - -} - -/** - * Expose `Extglob` - */ - -module.exports = Extglob; - - -/***/ }), -/* 713 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var extglob = __webpack_require__(695); -var nanomatch = __webpack_require__(685); -var regexNot = __webpack_require__(599); -var toRegex = __webpack_require__(582); -var not; - -/** - * Characters to use in negation regex (we want to "not" match - * characters that are matched by other parsers) - */ - -var TEXT = '([!@*?+]?\\(|\\)|\\[:?(?=.*?:?\\])|:?\\]|[*+?!^$.\\\\/])+'; -var createNotRegex = function(opts) { - return not || (not = textRegex(TEXT)); -}; - -/** - * Parsers - */ - -module.exports = function(snapdragon) { - var parsers = snapdragon.parser.parsers; - - // register nanomatch parsers - snapdragon.use(nanomatch.parsers); - - // get references to some specific nanomatch parsers before they - // are overridden by the extglob and/or parsers - var escape = parsers.escape; - var slash = parsers.slash; - var qmark = parsers.qmark; - var plus = parsers.plus; - var star = parsers.star; - var dot = parsers.dot; - - // register extglob parsers - snapdragon.use(extglob.parsers); - - // custom micromatch parsers - snapdragon.parser - .use(function() { - // override "notRegex" created in nanomatch parser - this.notRegex = /^\!+(?!\()/; - }) - // reset the referenced parsers - .capture('escape', escape) - .capture('slash', slash) - .capture('qmark', qmark) - .capture('star', star) - .capture('plus', plus) - .capture('dot', dot) - - /** - * Override `text` parser - */ - - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(createNotRegex(this.options)); - if (!m || !m[0]) return; - - // escape regex boundary characters and simple brackets - var val = m[0].replace(/([[\]^$])/g, '\\$1'); - - return pos({ - type: 'text', - val: val - }); - }); -}; - -/** - * Create text regex - */ - -function textRegex(pattern) { - var notStr = regexNot.create(pattern, {contains: true, strictClose: false}); - var prefix = '(?:[\\^]|\\\\|'; - return toRegex(prefix + notStr + ')', {strictClose: false}); -} - - -/***/ }), -/* 714 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = new (__webpack_require__(689))(); - - -/***/ }), -/* 715 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var utils = module.exports; -var path = __webpack_require__(4); - -/** - * Module dependencies - */ - -var Snapdragon = __webpack_require__(618); -utils.define = __webpack_require__(716); -utils.diff = __webpack_require__(693); -utils.extend = __webpack_require__(595); -utils.pick = __webpack_require__(694); -utils.typeOf = __webpack_require__(592); -utils.unique = __webpack_require__(600); - -/** - * Returns true if the platform is windows, or `path.sep` is `\\`. - * This is defined as a function to allow `path.sep` to be set in unit tests, - * or by the user, if there is a reason to do so. - * @return {Boolean} - */ - -utils.isWindows = function() { - return path.sep === '\\' || process.platform === 'win32'; -}; - -/** - * Get the `Snapdragon` instance to use - */ - -utils.instantiate = function(ast, options) { - var snapdragon; - // if an instance was created by `.parse`, use that instance - if (utils.typeOf(ast) === 'object' && ast.snapdragon) { - snapdragon = ast.snapdragon; - // if the user supplies an instance on options, use that instance - } else if (utils.typeOf(options) === 'object' && options.snapdragon) { - snapdragon = options.snapdragon; - // create a new instance - } else { - snapdragon = new Snapdragon(options); - } - - utils.define(snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strictErrors !== true) { - var open = last.nodes[0]; - var inner = last.nodes[1]; - if (last.type === 'bracket') { - if (inner.val.charAt(0) === '[') { - inner.val = '\\' + inner.val; - } - - } else { - open.val = '\\' + open.val; - var sibling = open.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - } - - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); - - return snapdragon; -}; - -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -utils.createKey = function(pattern, options) { - if (utils.typeOf(options) !== 'object') { - return pattern; - } - var val = pattern; - var keys = Object.keys(options); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - val += ';' + key + '=' + String(options[key]); - } - return val; -}; - -/** - * Cast `val` to an array - * @return {Array} - */ - -utils.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isString = function(val) { - return typeof val === 'string'; -}; - -/** - * Return true if `val` is a non-empty string - */ - -utils.isObject = function(val) { - return utils.typeOf(val) === 'object'; -}; - -/** - * Returns true if the given `str` has special characters - */ - -utils.hasSpecialChars = function(str) { - return /(?:(?:(^|\/)[!.])|[*?+()|\[\]{}]|[+@]\()/.test(str); -}; - -/** - * Escape regex characters in the given string - */ - -utils.escapeRegex = function(str) { - return str.replace(/[-[\]{}()^$|*+?.\\\/\s]/g, '\\$&'); -}; - -/** - * Normalize slashes in the given filepath. - * - * @param {String} `filepath` - * @return {String} - */ - -utils.toPosixPath = function(str) { - return str.replace(/\\+/g, '/'); -}; - -/** - * Strip backslashes before special characters in a string. - * - * @param {String} `str` - * @return {String} - */ - -utils.unescape = function(str) { - return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); -}; - -/** - * Strip the prefix from a filepath - * @param {String} `fp` - * @return {String} - */ - -utils.stripPrefix = function(str) { - if (str.charAt(0) !== '.') { - return str; - } - var ch = str.charAt(1); - if (utils.isSlash(ch)) { - return str.slice(2); - } - return str; -}; - -/** - * Returns true if the given str is an escaped or - * unescaped path character - */ - -utils.isSlash = function(str) { - return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; -}; - -/** - * Returns a function that returns true if the given - * pattern matches or contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.matchPath = function(pattern, options) { - return (options && options.contains) - ? utils.containsPattern(pattern, options) - : utils.equalsPattern(pattern, options); -}; - -/** - * Returns true if the given (original) filepath or unixified path are equal - * to the given pattern. - */ - -utils._equals = function(filepath, unixPath, pattern) { - return pattern === filepath || pattern === unixPath; -}; - -/** - * Returns true if the given (original) filepath or unixified path contain - * the given pattern. - */ - -utils._contains = function(filepath, unixPath, pattern) { - return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; -}; - -/** - * Returns a function that returns true if the given - * pattern is the same as a given `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.equalsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function fn(filepath) { - var equal = utils._equals(filepath, unixify(filepath), pattern); - if (equal === true || options.nocase !== true) { - return equal; - } - var lower = filepath.toLowerCase(); - return utils._equals(lower, unixify(lower), pattern); - }; -}; - -/** - * Returns a function that returns true if the given - * pattern contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ - -utils.containsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function(filepath) { - var contains = utils._contains(filepath, unixify(filepath), pattern); - if (contains === true || options.nocase !== true) { - return contains; - } - var lower = filepath.toLowerCase(); - return utils._contains(lower, unixify(lower), pattern); - }; -}; - -/** - * Returns a function that returns true if the given - * regex matches the `filename` of a file path. - * - * @param {RegExp} `re` Matching regex - * @return {Function} - */ - -utils.matchBasename = function(re) { - return function(filepath) { - return re.test(path.basename(filepath)); - }; -}; - -/** - * Determines the filepath to return based on the provided options. - * @return {any} - */ - -utils.value = function(str, unixify, options) { - if (options && options.unixify === false) { - return str; - } - return unixify(str); -}; - -/** - * Returns a function that normalizes slashes in a string to forward - * slashes, strips `./` from beginning of paths, and optionally unescapes - * special characters. - * @return {Function} - */ - -utils.unixify = function(options) { - options = options || {}; - return function(filepath) { - if (utils.isWindows() || options.unixify === true) { - filepath = utils.toPosixPath(filepath); - } - if (options.stripPrefix !== false) { - filepath = utils.stripPrefix(filepath); - } - if (options.unescape === true) { - filepath = utils.unescape(filepath); - } - return filepath; - }; -}; - - -/***/ }), -/* 716 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ - - - -var isobject = __webpack_require__(590); -var isDescriptor = __webpack_require__(591); -var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) - ? Reflect.defineProperty - : Object.defineProperty; - -module.exports = function defineProperty(obj, key, val) { - if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { - throw new TypeError('expected an object, function, or array'); - } - - if (typeof key !== 'string') { - throw new TypeError('expected "key" to be a string'); - } - - if (isDescriptor(val)) { - define(obj, key, val); - return obj; - } - - define(obj, key, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); - - return obj; -}; - - -/***/ }), -/* 717 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(718); -var reader_1 = __webpack_require__(731); -var fs_stream_1 = __webpack_require__(735); -var ReaderAsync = /** @class */ (function (_super) { - __extends(ReaderAsync, _super); - function ReaderAsync() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderAsync.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_stream_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use async API to read entries for Task. - */ - ReaderAsync.prototype.read = function (task) { - var _this = this; - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - var entries = []; - return new Promise(function (resolve, reject) { - var stream = _this.api(root, task, options); - stream.on('error', function (err) { - _this.isEnoentCodeError(err) ? resolve([]) : reject(err); - stream.pause(); - }); - stream.on('data', function (entry) { return entries.push(_this.transform(entry)); }); - stream.on('end', function () { return resolve(entries); }); - }); - }; - /** - * Returns founded paths. - */ - ReaderAsync.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderAsync.prototype.dynamicApi = function (root, options) { - return readdir.readdirStreamStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderAsync.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderAsync; -}(reader_1.default)); -exports.default = ReaderAsync; - - -/***/ }), -/* 718 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const readdirSync = __webpack_require__(719); -const readdirAsync = __webpack_require__(727); -const readdirStream = __webpack_require__(730); - -module.exports = exports = readdirAsyncPath; -exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; -exports.readdirAsyncStat = exports.async.stat = readdirAsyncStat; -exports.readdirStream = exports.stream = readdirStreamPath; -exports.readdirStreamStat = exports.stream.stat = readdirStreamStat; -exports.readdirSync = exports.sync = readdirSyncPath; -exports.readdirSyncStat = exports.sync.stat = readdirSyncStat; - -/** - * Synchronous readdir that returns an array of string paths. - * - * @param {string} dir - * @param {object} [options] - * @returns {string[]} - */ -function readdirSyncPath (dir, options) { - return readdirSync(dir, options, {}); -} - -/** - * Synchronous readdir that returns results as an array of {@link fs.Stats} objects - * - * @param {string} dir - * @param {object} [options] - * @returns {fs.Stats[]} - */ -function readdirSyncStat (dir, options) { - return readdirSync(dir, options, { stats: true }); -} - -/** - * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). - * Results are an array of path strings. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @returns {Promise} - */ -function readdirAsyncPath (dir, options, callback) { - return readdirAsync(dir, options, callback, {}); -} - -/** - * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). - * Results are an array of {@link fs.Stats} objects. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @returns {Promise} - */ -function readdirAsyncStat (dir, options, callback) { - return readdirAsync(dir, options, callback, { stats: true }); -} - -/** - * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}). - * All stream data events ("data", "file", "directory", "symlink") are passed a path string. - * - * @param {string} dir - * @param {object} [options] - * @returns {stream.Readable} - */ -function readdirStreamPath (dir, options) { - return readdirStream(dir, options, {}); -} - -/** - * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}) - * All stream data events ("data", "file", "directory", "symlink") are passed an {@link fs.Stats} object. - * - * @param {string} dir - * @param {object} [options] - * @returns {stream.Readable} - */ -function readdirStreamStat (dir, options) { - return readdirStream(dir, options, { stats: true }); -} - - -/***/ }), -/* 719 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = readdirSync; - -const DirectoryReader = __webpack_require__(720); - -let syncFacade = { - fs: __webpack_require__(725), - forEach: __webpack_require__(726), - sync: true -}; - -/** - * Returns the buffered output from a synchronous {@link DirectoryReader}. - * - * @param {string} dir - * @param {object} [options] - * @param {object} internalOptions - */ -function readdirSync (dir, options, internalOptions) { - internalOptions.facade = syncFacade; - - let reader = new DirectoryReader(dir, options, internalOptions); - let stream = reader.stream; - - let results = []; - let data = stream.read(); - while (data !== null) { - results.push(data); - data = stream.read(); - } - - return results; -} - - -/***/ }), -/* 720 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const Readable = __webpack_require__(138).Readable; -const EventEmitter = __webpack_require__(157).EventEmitter; -const path = __webpack_require__(4); -const normalizeOptions = __webpack_require__(721); -const stat = __webpack_require__(723); -const call = __webpack_require__(724); - -/** - * Asynchronously reads the contents of a directory and streams the results - * via a {@link stream.Readable}. - */ -class DirectoryReader { - /** - * @param {string} dir - The absolute or relative directory path to read - * @param {object} [options] - User-specified options, if any (see {@link normalizeOptions}) - * @param {object} internalOptions - Internal options that aren't part of the public API - * @class - */ - constructor (dir, options, internalOptions) { - this.options = options = normalizeOptions(options, internalOptions); - - // Indicates whether we should keep reading - // This is set false if stream.Readable.push() returns false. - this.shouldRead = true; - - // The directories to read - // (initialized with the top-level directory) - this.queue = [{ - path: dir, - basePath: options.basePath, - posixBasePath: options.posixBasePath, - depth: 0 - }]; - - // The number of directories that are currently being processed - this.pending = 0; - - // The data that has been read, but not yet emitted - this.buffer = []; - - this.stream = new Readable({ objectMode: true }); - this.stream._read = () => { - // Start (or resume) reading - this.shouldRead = true; - - // If we have data in the buffer, then send the next chunk - if (this.buffer.length > 0) { - this.pushFromBuffer(); - } - - // If we have directories queued, then start processing the next one - if (this.queue.length > 0) { - if (this.options.facade.sync) { - while (this.queue.length > 0) { - this.readNextDirectory(); - } - } - else { - this.readNextDirectory(); - } - } - - this.checkForEOF(); - }; - } - - /** - * Reads the next directory in the queue - */ - readNextDirectory () { - let facade = this.options.facade; - let dir = this.queue.shift(); - this.pending++; - - // Read the directory listing - call.safe(facade.fs.readdir, dir.path, (err, items) => { - if (err) { - // fs.readdir threw an error - this.emit('error', err); - return this.finishedReadingDirectory(); - } - - try { - // Process each item in the directory (simultaneously, if async) - facade.forEach( - items, - this.processItem.bind(this, dir), - this.finishedReadingDirectory.bind(this, dir) - ); - } - catch (err2) { - // facade.forEach threw an error - // (probably because fs.readdir returned an invalid result) - this.emit('error', err2); - this.finishedReadingDirectory(); - } - }); - } - - /** - * This method is called after all items in a directory have been processed. - * - * NOTE: This does not necessarily mean that the reader is finished, since there may still - * be other directories queued or pending. - */ - finishedReadingDirectory () { - this.pending--; - - if (this.shouldRead) { - // If we have directories queued, then start processing the next one - if (this.queue.length > 0 && this.options.facade.async) { - this.readNextDirectory(); - } - - this.checkForEOF(); - } - } - - /** - * Determines whether the reader has finished processing all items in all directories. - * If so, then the "end" event is fired (via {@Readable#push}) - */ - checkForEOF () { - if (this.buffer.length === 0 && // The stuff we've already read - this.pending === 0 && // The stuff we're currently reading - this.queue.length === 0) { // The stuff we haven't read yet - // There's no more stuff! - this.stream.push(null); - } - } - - /** - * Processes a single item in a directory. - * - * If the item is a directory, and `option.deep` is enabled, then the item will be added - * to the directory queue. - * - * If the item meets the filter criteria, then it will be emitted to the reader's stream. - * - * @param {object} dir - A directory object from the queue - * @param {string} item - The name of the item (name only, no path) - * @param {function} done - A callback function that is called after the item has been processed - */ - processItem (dir, item, done) { - let stream = this.stream; - let options = this.options; - - let itemPath = dir.basePath + item; - let posixPath = dir.posixBasePath + item; - let fullPath = path.join(dir.path, item); - - // If `options.deep` is a number, and we've already recursed to the max depth, - // then there's no need to check fs.Stats to know if it's a directory. - // If `options.deep` is a function, then we'll need fs.Stats - let maxDepthReached = dir.depth >= options.recurseDepth; - - // Do we need to call `fs.stat`? - let needStats = - !maxDepthReached || // we need the fs.Stats to know if it's a directory - options.stats || // the user wants fs.Stats objects returned - options.recurseFn || // we need fs.Stats for the recurse function - options.filterFn || // we need fs.Stats for the filter function - EventEmitter.listenerCount(stream, 'file') || // we need the fs.Stats to know if it's a file - EventEmitter.listenerCount(stream, 'directory') || // we need the fs.Stats to know if it's a directory - EventEmitter.listenerCount(stream, 'symlink'); // we need the fs.Stats to know if it's a symlink - - // If we don't need stats, then exit early - if (!needStats) { - if (this.filter(itemPath, posixPath)) { - this.pushOrBuffer({ data: itemPath }); - } - return done(); - } - - // Get the fs.Stats object for this path - stat(options.facade.fs, fullPath, (err, stats) => { - if (err) { - // fs.stat threw an error - this.emit('error', err); - return done(); - } - - try { - // Add the item's path to the fs.Stats object - // The base of this path, and its separators are determined by the options - // (i.e. options.basePath and options.sep) - stats.path = itemPath; - - // Add depth of the path to the fs.Stats object for use this in the filter function - stats.depth = dir.depth; - - if (this.shouldRecurse(stats, posixPath, maxDepthReached)) { - // Add this subdirectory to the queue - this.queue.push({ - path: fullPath, - basePath: itemPath + options.sep, - posixBasePath: posixPath + '/', - depth: dir.depth + 1, - }); - } - - // Determine whether this item matches the filter criteria - if (this.filter(stats, posixPath)) { - this.pushOrBuffer({ - data: options.stats ? stats : itemPath, - file: stats.isFile(), - directory: stats.isDirectory(), - symlink: stats.isSymbolicLink(), - }); - } - - done(); - } - catch (err2) { - // An error occurred while processing the item - // (probably during a user-specified function, such as options.deep, options.filter, etc.) - this.emit('error', err2); - done(); - } - }); - } - - /** - * Pushes the given chunk of data to the stream, or adds it to the buffer, - * depending on the state of the stream. - * - * @param {object} chunk - */ - pushOrBuffer (chunk) { - // Add the chunk to the buffer - this.buffer.push(chunk); - - // If we're still reading, then immediately emit the next chunk in the buffer - // (which may or may not be the chunk that we just added) - if (this.shouldRead) { - this.pushFromBuffer(); - } - } - - /** - * Immediately pushes the next chunk in the buffer to the reader's stream. - * The "data" event will always be fired (via {@link Readable#push}). - * In addition, the "file", "directory", and/or "symlink" events may be fired, - * depending on the type of properties of the chunk. - */ - pushFromBuffer () { - let stream = this.stream; - let chunk = this.buffer.shift(); - - // Stream the data - try { - this.shouldRead = stream.push(chunk.data); - } - catch (err) { - this.emit('error', err); - } - - // Also emit specific events, based on the type of chunk - chunk.file && this.emit('file', chunk.data); - chunk.symlink && this.emit('symlink', chunk.data); - chunk.directory && this.emit('directory', chunk.data); - } - - /** - * Determines whether the given directory meets the user-specified recursion criteria. - * If the user didn't specify recursion criteria, then this function will default to true. - * - * @param {fs.Stats} stats - The directory's {@link fs.Stats} object - * @param {string} posixPath - The item's POSIX path (used for glob matching) - * @param {boolean} maxDepthReached - Whether we've already crawled the user-specified depth - * @returns {boolean} - */ - shouldRecurse (stats, posixPath, maxDepthReached) { - let options = this.options; - - if (maxDepthReached) { - // We've already crawled to the maximum depth. So no more recursion. - return false; - } - else if (!stats.isDirectory()) { - // It's not a directory. So don't try to crawl it. - return false; - } - else if (options.recurseGlob) { - // Glob patterns are always tested against the POSIX path, even on Windows - // https://github.com/isaacs/node-glob#windows - return options.recurseGlob.test(posixPath); - } - else if (options.recurseRegExp) { - // Regular expressions are tested against the normal path - // (based on the OS or options.sep) - return options.recurseRegExp.test(stats.path); - } - else if (options.recurseFn) { - try { - // Run the user-specified recursion criteria - return options.recurseFn.call(null, stats); - } - catch (err) { - // An error occurred in the user's code. - // In Sync and Async modes, this will return an error. - // In Streaming mode, we emit an "error" event, but continue processing - this.emit('error', err); - } - } - else { - // No recursion function was specified, and we're within the maximum depth. - // So crawl this directory. - return true; - } - } - - /** - * Determines whether the given item meets the user-specified filter criteria. - * If the user didn't specify a filter, then this function will always return true. - * - * @param {string|fs.Stats} value - Either the item's path, or the item's {@link fs.Stats} object - * @param {string} posixPath - The item's POSIX path (used for glob matching) - * @returns {boolean} - */ - filter (value, posixPath) { - let options = this.options; - - if (options.filterGlob) { - // Glob patterns are always tested against the POSIX path, even on Windows - // https://github.com/isaacs/node-glob#windows - return options.filterGlob.test(posixPath); - } - else if (options.filterRegExp) { - // Regular expressions are tested against the normal path - // (based on the OS or options.sep) - return options.filterRegExp.test(value.path || value); - } - else if (options.filterFn) { - try { - // Run the user-specified filter function - return options.filterFn.call(null, value); - } - catch (err) { - // An error occurred in the user's code. - // In Sync and Async modes, this will return an error. - // In Streaming mode, we emit an "error" event, but continue processing - this.emit('error', err); - } - } - else { - // No filter was specified, so match everything - return true; - } - } - - /** - * Emits an event. If one of the event listeners throws an error, - * then an "error" event is emitted. - * - * @param {string} eventName - * @param {*} data - */ - emit (eventName, data) { - let stream = this.stream; - - try { - stream.emit(eventName, data); - } - catch (err) { - if (eventName === 'error') { - // Don't recursively emit "error" events. - // If the first one fails, then just throw - throw err; - } - else { - stream.emit('error', err); - } - } - } -} - -module.exports = DirectoryReader; - - -/***/ }), -/* 721 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const path = __webpack_require__(4); -const globToRegExp = __webpack_require__(722); - -module.exports = normalizeOptions; - -let isWindows = /^win/.test(process.platform); - -/** - * @typedef {Object} FSFacade - * @property {fs.readdir} readdir - * @property {fs.stat} stat - * @property {fs.lstat} lstat - */ - -/** - * Validates and normalizes the options argument - * - * @param {object} [options] - User-specified options, if any - * @param {object} internalOptions - Internal options that aren't part of the public API - * - * @param {number|boolean|function} [options.deep] - * The number of directories to recursively traverse. Any falsy value or negative number will - * default to zero, so only the top-level contents will be returned. Set to `true` or `Infinity` - * to traverse all subdirectories. Or provide a function that accepts a {@link fs.Stats} object - * and returns a truthy value if the directory's contents should be crawled. - * - * @param {function|string|RegExp} [options.filter] - * A function that accepts a {@link fs.Stats} object and returns a truthy value if the data should - * be returned. Or a RegExp or glob string pattern, to filter by file name. - * - * @param {string} [options.sep] - * The path separator to use. By default, the OS-specific separator will be used, but this can be - * set to a specific value to ensure consistency across platforms. - * - * @param {string} [options.basePath] - * The base path to prepend to each result. If empty, then all results will be relative to `dir`. - * - * @param {FSFacade} [options.fs] - * Synchronous or asynchronous facades for Node.js File System module - * - * @param {object} [internalOptions.facade] - * Synchronous or asynchronous facades for various methods, including for the Node.js File System module - * - * @param {boolean} [internalOptions.emit] - * Indicates whether the reader should emit "file", "directory", and "symlink" events - * - * @param {boolean} [internalOptions.stats] - * Indicates whether the reader should emit {@link fs.Stats} objects instead of path strings - * - * @returns {object} - */ -function normalizeOptions (options, internalOptions) { - if (options === null || options === undefined) { - options = {}; - } - else if (typeof options !== 'object') { - throw new TypeError('options must be an object'); - } - - let recurseDepth, recurseFn, recurseRegExp, recurseGlob, deep = options.deep; - if (deep === null || deep === undefined) { - recurseDepth = 0; - } - else if (typeof deep === 'boolean') { - recurseDepth = deep ? Infinity : 0; - } - else if (typeof deep === 'number') { - if (deep < 0 || isNaN(deep)) { - throw new Error('options.deep must be a positive number'); - } - else if (Math.floor(deep) !== deep) { - throw new Error('options.deep must be an integer'); - } - else { - recurseDepth = deep; - } - } - else if (typeof deep === 'function') { - recurseDepth = Infinity; - recurseFn = deep; - } - else if (deep instanceof RegExp) { - recurseDepth = Infinity; - recurseRegExp = deep; - } - else if (typeof deep === 'string' && deep.length > 0) { - recurseDepth = Infinity; - recurseGlob = globToRegExp(deep, { extended: true, globstar: true }); - } - else { - throw new TypeError('options.deep must be a boolean, number, function, regular expression, or glob pattern'); - } - - let filterFn, filterRegExp, filterGlob, filter = options.filter; - if (filter !== null && filter !== undefined) { - if (typeof filter === 'function') { - filterFn = filter; - } - else if (filter instanceof RegExp) { - filterRegExp = filter; - } - else if (typeof filter === 'string' && filter.length > 0) { - filterGlob = globToRegExp(filter, { extended: true, globstar: true }); - } - else { - throw new TypeError('options.filter must be a function, regular expression, or glob pattern'); - } - } - - let sep = options.sep; - if (sep === null || sep === undefined) { - sep = path.sep; - } - else if (typeof sep !== 'string') { - throw new TypeError('options.sep must be a string'); - } - - let basePath = options.basePath; - if (basePath === null || basePath === undefined) { - basePath = ''; - } - else if (typeof basePath === 'string') { - // Append a path separator to the basePath, if necessary - if (basePath && basePath.substr(-1) !== sep) { - basePath += sep; - } - } - else { - throw new TypeError('options.basePath must be a string'); - } - - // Convert the basePath to POSIX (forward slashes) - // so that glob pattern matching works consistently, even on Windows - let posixBasePath = basePath; - if (posixBasePath && sep !== '/') { - posixBasePath = posixBasePath.replace(new RegExp('\\' + sep, 'g'), '/'); - - /* istanbul ignore if */ - if (isWindows) { - // Convert Windows root paths (C:\) and UNCs (\\) to POSIX root paths - posixBasePath = posixBasePath.replace(/^([a-zA-Z]\:\/|\/\/)/, '/'); - } - } - - // Determine which facade methods to use - let facade; - if (options.fs === null || options.fs === undefined) { - // The user didn't provide their own facades, so use our internal ones - facade = internalOptions.facade; - } - else if (typeof options.fs === 'object') { - // Merge the internal facade methods with the user-provided `fs` facades - facade = Object.assign({}, internalOptions.facade); - facade.fs = Object.assign({}, internalOptions.facade.fs, options.fs); - } - else { - throw new TypeError('options.fs must be an object'); - } - - return { - recurseDepth, - recurseFn, - recurseRegExp, - recurseGlob, - filterFn, - filterRegExp, - filterGlob, - sep, - basePath, - posixBasePath, - facade, - emit: !!internalOptions.emit, - stats: !!internalOptions.stats, - }; -} - - -/***/ }), -/* 722 */ -/***/ (function(module, exports) { - -module.exports = function (glob, opts) { - if (typeof glob !== 'string') { - throw new TypeError('Expected a string'); - } - - var str = String(glob); - - // The regexp we are building, as a string. - var reStr = ""; - - // Whether we are matching so called "extended" globs (like bash) and should - // support single character matching, matching ranges of characters, group - // matching, etc. - var extended = opts ? !!opts.extended : false; - - // When globstar is _false_ (default), '/foo/*' is translated a regexp like - // '^\/foo\/.*$' which will match any string beginning with '/foo/' - // When globstar is _true_, '/foo/*' is translated to regexp like - // '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT - // which does not have a '/' to the right of it. - // E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but - // these will not '/foo/bar/baz', '/foo/bar/baz.txt' - // Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when - // globstar is _false_ - var globstar = opts ? !!opts.globstar : false; - - // If we are doing extended matching, this boolean is true when we are inside - // a group (eg {*.html,*.js}), and false otherwise. - var inGroup = false; - - // RegExp flags (eg "i" ) to pass in to RegExp constructor. - var flags = opts && typeof( opts.flags ) === "string" ? opts.flags : ""; - - var c; - for (var i = 0, len = str.length; i < len; i++) { - c = str[i]; - - switch (c) { - case "\\": - case "/": - case "$": - case "^": - case "+": - case ".": - case "(": - case ")": - case "=": - case "!": - case "|": - reStr += "\\" + c; - break; - - case "?": - if (extended) { - reStr += "."; - break; - } - - case "[": - case "]": - if (extended) { - reStr += c; - break; - } - - case "{": - if (extended) { - inGroup = true; - reStr += "("; - break; - } - - case "}": - if (extended) { - inGroup = false; - reStr += ")"; - break; - } - - case ",": - if (inGroup) { - reStr += "|"; - break; - } - reStr += "\\" + c; - break; - - case "*": - // Move over all consecutive "*"'s. - // Also store the previous and next characters - var prevChar = str[i - 1]; - var starCount = 1; - while(str[i + 1] === "*") { - starCount++; - i++; - } - var nextChar = str[i + 1]; - - if (!globstar) { - // globstar is disabled, so treat any number of "*" as one - reStr += ".*"; - } else { - // globstar is enabled, so determine if this is a globstar segment - var isGlobstar = starCount > 1 // multiple "*"'s - && (prevChar === "/" || prevChar === undefined) // from the start of the segment - && (nextChar === "/" || nextChar === undefined) // to the end of the segment - - if (isGlobstar) { - // it's a globstar, so match zero or more path segments - reStr += "(?:[^/]*(?:\/|$))*"; - i++; // move over the "/" - } else { - // it's not a globstar, so only match one path segment - reStr += "[^/]*"; - } - } - break; - - default: - reStr += c; - } - } - - // When regexp 'g' flag is specified don't - // constrain the regular expression with ^ & $ - if (!flags || !~flags.indexOf('g')) { - reStr = "^" + reStr + "$"; - } - - return new RegExp(reStr, flags); -}; - - -/***/ }), -/* 723 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const call = __webpack_require__(724); - -module.exports = stat; - -/** - * Retrieves the {@link fs.Stats} for the given path. If the path is a symbolic link, - * then the Stats of the symlink's target are returned instead. If the symlink is broken, - * then the Stats of the symlink itself are returned. - * - * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module - * @param {string} path - The path to return stats for - * @param {function} callback - */ -function stat (fs, path, callback) { - let isSymLink = false; - - call.safe(fs.lstat, path, (err, lstats) => { - if (err) { - // fs.lstat threw an eror - return callback(err); - } - - try { - isSymLink = lstats.isSymbolicLink(); - } - catch (err2) { - // lstats.isSymbolicLink() threw an error - // (probably because fs.lstat returned an invalid result) - return callback(err2); - } - - if (isSymLink) { - // Try to resolve the symlink - symlinkStat(fs, path, lstats, callback); - } - else { - // It's not a symlink, so return the stats as-is - callback(null, lstats); - } - }); -} - -/** - * Retrieves the {@link fs.Stats} for the target of the given symlink. - * If the symlink is broken, then the Stats of the symlink itself are returned. - * - * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module - * @param {string} path - The path of the symlink to return stats for - * @param {object} lstats - The stats of the symlink - * @param {function} callback - */ -function symlinkStat (fs, path, lstats, callback) { - call.safe(fs.stat, path, (err, stats) => { - if (err) { - // The symlink is broken, so return the stats for the link itself - return callback(null, lstats); - } - - try { - // Return the stats for the resolved symlink target, - // and override the `isSymbolicLink` method to indicate that it's a symlink - stats.isSymbolicLink = () => true; - } - catch (err2) { - // Setting stats.isSymbolicLink threw an error - // (probably because fs.stat returned an invalid result) - return callback(err2); - } - - callback(null, stats); - }); -} - - -/***/ }), -/* 724 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -let call = module.exports = { - safe: safeCall, - once: callOnce, -}; - -/** - * Calls a function with the given arguments, and ensures that the error-first callback is _always_ - * invoked exactly once, even if the function throws an error. - * - * @param {function} fn - The function to invoke - * @param {...*} args - The arguments to pass to the function. The final argument must be a callback function. - */ -function safeCall (fn, args) { - // Get the function arguments as an array - args = Array.prototype.slice.call(arguments, 1); - - // Replace the callback function with a wrapper that ensures it will only be called once - let callback = call.once(args.pop()); - args.push(callback); - - try { - fn.apply(null, args); - } - catch (err) { - callback(err); - } -} - -/** - * Returns a wrapper function that ensures the given callback function is only called once. - * Subsequent calls are ignored, unless the first argument is an Error, in which case the - * error is thrown. - * - * @param {function} fn - The function that should only be called once - * @returns {function} - */ -function callOnce (fn) { - let fulfilled = false; - - return function onceWrapper (err) { - if (!fulfilled) { - fulfilled = true; - return fn.apply(this, arguments); - } - else if (err) { - // The callback has already been called, but now an error has occurred - // (most likely inside the callback function). So re-throw the error, - // so it gets handled further up the call stack - throw err; - } - }; -} - - -/***/ }), -/* 725 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const fs = __webpack_require__(134); -const call = __webpack_require__(724); - -/** - * A facade around {@link fs.readdirSync} that allows it to be called - * the same way as {@link fs.readdir}. - * - * @param {string} dir - * @param {function} callback - */ -exports.readdir = function (dir, callback) { - // Make sure the callback is only called once - callback = call.once(callback); - - try { - let items = fs.readdirSync(dir); - callback(null, items); - } - catch (err) { - callback(err); - } -}; - -/** - * A facade around {@link fs.statSync} that allows it to be called - * the same way as {@link fs.stat}. - * - * @param {string} path - * @param {function} callback - */ -exports.stat = function (path, callback) { - // Make sure the callback is only called once - callback = call.once(callback); - - try { - let stats = fs.statSync(path); - callback(null, stats); - } - catch (err) { - callback(err); - } -}; - -/** - * A facade around {@link fs.lstatSync} that allows it to be called - * the same way as {@link fs.lstat}. - * - * @param {string} path - * @param {function} callback - */ -exports.lstat = function (path, callback) { - // Make sure the callback is only called once - callback = call.once(callback); - - try { - let stats = fs.lstatSync(path); - callback(null, stats); - } - catch (err) { - callback(err); - } -}; - - -/***/ }), -/* 726 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = syncForEach; - -/** - * A facade that allows {@link Array.forEach} to be called as though it were asynchronous. - * - * @param {array} array - The array to iterate over - * @param {function} iterator - The function to call for each item in the array - * @param {function} done - The function to call when all iterators have completed - */ -function syncForEach (array, iterator, done) { - array.forEach(item => { - iterator(item, () => { - // Note: No error-handling here because this is currently only ever called - // by DirectoryReader, which never passes an `error` parameter to the callback. - // Instead, DirectoryReader emits an "error" event if an error occurs. - }); - }); - - done(); -} - - -/***/ }), -/* 727 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = readdirAsync; - -const maybe = __webpack_require__(728); -const DirectoryReader = __webpack_require__(720); - -let asyncFacade = { - fs: __webpack_require__(134), - forEach: __webpack_require__(729), - async: true -}; - -/** - * Returns the buffered output from an asynchronous {@link DirectoryReader}, - * via an error-first callback or a {@link Promise}. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @param {object} internalOptions - */ -function readdirAsync (dir, options, callback, internalOptions) { - if (typeof options === 'function') { - callback = options; - options = undefined; - } - - return maybe(callback, new Promise(((resolve, reject) => { - let results = []; - - internalOptions.facade = asyncFacade; - - let reader = new DirectoryReader(dir, options, internalOptions); - let stream = reader.stream; - - stream.on('error', err => { - reject(err); - stream.pause(); - }); - stream.on('data', result => { - results.push(result); - }); - stream.on('end', () => { - resolve(results); - }); - }))); -} - - -/***/ }), -/* 728 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var next = (global.process && process.nextTick) || global.setImmediate || function (f) { - setTimeout(f, 0) -} - -module.exports = function maybe (cb, promise) { - if (cb) { - promise - .then(function (result) { - next(function () { cb(null, result) }) - }, function (err) { - next(function () { cb(err) }) - }) - return undefined - } - else { - return promise - } -} - - -/***/ }), -/* 729 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = asyncForEach; - -/** - * Simultaneously processes all items in the given array. - * - * @param {array} array - The array to iterate over - * @param {function} iterator - The function to call for each item in the array - * @param {function} done - The function to call when all iterators have completed - */ -function asyncForEach (array, iterator, done) { - if (array.length === 0) { - // NOTE: Normally a bad idea to mix sync and async, but it's safe here because - // of the way that this method is currently used by DirectoryReader. - done(); - return; - } - - // Simultaneously process all items in the array. - let pending = array.length; - array.forEach(item => { - iterator(item, () => { - if (--pending === 0) { - done(); - } - }); - }); -} - - -/***/ }), -/* 730 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = readdirStream; - -const DirectoryReader = __webpack_require__(720); - -let streamFacade = { - fs: __webpack_require__(134), - forEach: __webpack_require__(729), - async: true -}; - -/** - * Returns the {@link stream.Readable} of an asynchronous {@link DirectoryReader}. - * - * @param {string} dir - * @param {object} [options] - * @param {object} internalOptions - */ -function readdirStream (dir, options, internalOptions) { - internalOptions.facade = streamFacade; - - let reader = new DirectoryReader(dir, options, internalOptions); - return reader.stream; -} - - -/***/ }), -/* 731 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(4); -var deep_1 = __webpack_require__(732); -var entry_1 = __webpack_require__(734); -var pathUtil = __webpack_require__(733); -var Reader = /** @class */ (function () { - function Reader(options) { - this.options = options; - this.micromatchOptions = this.getMicromatchOptions(); - this.entryFilter = new entry_1.default(options, this.micromatchOptions); - this.deepFilter = new deep_1.default(options, this.micromatchOptions); - } - /** - * Returns root path to scanner. - */ - Reader.prototype.getRootDirectory = function (task) { - return path.resolve(this.options.cwd, task.base); - }; - /** - * Returns options for reader. - */ - Reader.prototype.getReaderOptions = function (task) { - return { - basePath: task.base === '.' ? '' : task.base, - filter: this.entryFilter.getFilter(task.positive, task.negative), - deep: this.deepFilter.getFilter(task.positive, task.negative), - sep: '/' - }; - }; - /** - * Returns options for micromatch. - */ - Reader.prototype.getMicromatchOptions = function () { - return { - dot: this.options.dot, - nobrace: !this.options.brace, - noglobstar: !this.options.globstar, - noext: !this.options.extension, - nocase: !this.options.case, - matchBase: this.options.matchBase - }; - }; - /** - * Returns transformed entry. - */ - Reader.prototype.transform = function (entry) { - if (this.options.absolute) { - entry.path = pathUtil.makeAbsolute(this.options.cwd, entry.path); - } - if (this.options.markDirectories && entry.isDirectory()) { - entry.path += '/'; - } - var item = this.options.stats ? entry : entry.path; - if (this.options.transform === null) { - return item; - } - return this.options.transform(item); - }; - /** - * Returns true if error has ENOENT code. - */ - Reader.prototype.isEnoentCodeError = function (err) { - return err.code === 'ENOENT'; - }; - return Reader; -}()); -exports.default = Reader; - - -/***/ }), -/* 732 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(733); -var patternUtils = __webpack_require__(579); -var DeepFilter = /** @class */ (function () { - function DeepFilter(options, micromatchOptions) { - this.options = options; - this.micromatchOptions = micromatchOptions; - } - /** - * Returns filter for directories. - */ - DeepFilter.prototype.getFilter = function (positive, negative) { - var _this = this; - var maxPatternDepth = this.getMaxPatternDepth(positive); - var negativeRe = this.getNegativePatternsRe(negative); - return function (entry) { return _this.filter(entry, negativeRe, maxPatternDepth); }; - }; - /** - * Returns max depth of the provided patterns. - */ - DeepFilter.prototype.getMaxPatternDepth = function (patterns) { - var globstar = patterns.some(patternUtils.hasGlobStar); - return globstar ? Infinity : patternUtils.getMaxNaivePatternsDepth(patterns); - }; - /** - * Returns RegExp's for patterns that can affect the depth of reading. - */ - DeepFilter.prototype.getNegativePatternsRe = function (patterns) { - var affectDepthOfReadingPatterns = patterns.filter(patternUtils.isAffectDepthOfReadingPattern); - return patternUtils.convertPatternsToRe(affectDepthOfReadingPatterns, this.micromatchOptions); - }; - /** - * Returns «true» for directory that should be read. - */ - DeepFilter.prototype.filter = function (entry, negativeRe, maxPatternDepth) { - if (this.isSkippedByDeepOption(entry.depth)) { - return false; - } - if (this.isSkippedByMaxPatternDepth(entry.depth, maxPatternDepth)) { - return false; - } - if (this.isSkippedSymlinkedDirectory(entry)) { - return false; - } - if (this.isSkippedDotDirectory(entry)) { - return false; - } - return this.isSkippedByNegativePatterns(entry, negativeRe); - }; - /** - * Returns «true» when the «deep» option is disabled or number and depth of the entry is greater that the option value. - */ - DeepFilter.prototype.isSkippedByDeepOption = function (entryDepth) { - return !this.options.deep || (typeof this.options.deep === 'number' && entryDepth >= this.options.deep); - }; - /** - * Returns «true» when depth parameter is not an Infinity and entry depth greater that the parameter value. - */ - DeepFilter.prototype.isSkippedByMaxPatternDepth = function (entryDepth, maxPatternDepth) { - return maxPatternDepth !== Infinity && entryDepth >= maxPatternDepth; - }; - /** - * Returns «true» for symlinked directory if the «followSymlinkedDirectories» option is disabled. - */ - DeepFilter.prototype.isSkippedSymlinkedDirectory = function (entry) { - return !this.options.followSymlinkedDirectories && entry.isSymbolicLink(); - }; - /** - * Returns «true» for a directory whose name starts with a period if «dot» option is disabled. - */ - DeepFilter.prototype.isSkippedDotDirectory = function (entry) { - return !this.options.dot && pathUtils.isDotDirectory(entry.path); - }; - /** - * Returns «true» for a directory whose path math to any negative pattern. - */ - DeepFilter.prototype.isSkippedByNegativePatterns = function (entry, negativeRe) { - return !patternUtils.matchAny(entry.path, negativeRe); - }; - return DeepFilter; -}()); -exports.default = DeepFilter; - - -/***/ }), -/* 733 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(4); -/** - * Returns «true» if the last partial of the path starting with a period. - */ -function isDotDirectory(filepath) { - return path.basename(filepath).startsWith('.'); -} -exports.isDotDirectory = isDotDirectory; -/** - * Convert a windows-like path to a unix-style path. - */ -function normalize(filepath) { - return filepath.replace(/\\/g, '/'); -} -exports.normalize = normalize; -/** - * Returns normalized absolute path of provided filepath. - */ -function makeAbsolute(cwd, filepath) { - return normalize(path.resolve(cwd, filepath)); -} -exports.makeAbsolute = makeAbsolute; - - -/***/ }), -/* 734 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(733); -var patternUtils = __webpack_require__(579); -var EntryFilter = /** @class */ (function () { - function EntryFilter(options, micromatchOptions) { - this.options = options; - this.micromatchOptions = micromatchOptions; - this.index = new Map(); - } - /** - * Returns filter for directories. - */ - EntryFilter.prototype.getFilter = function (positive, negative) { - var _this = this; - var positiveRe = patternUtils.convertPatternsToRe(positive, this.micromatchOptions); - var negativeRe = patternUtils.convertPatternsToRe(negative, this.micromatchOptions); - return function (entry) { return _this.filter(entry, positiveRe, negativeRe); }; - }; - /** - * Returns true if entry must be added to result. - */ - EntryFilter.prototype.filter = function (entry, positiveRe, negativeRe) { - // Exclude duplicate results - if (this.options.unique) { - if (this.isDuplicateEntry(entry)) { - return false; - } - this.createIndexRecord(entry); - } - // Filter files and directories by options - if (this.onlyFileFilter(entry) || this.onlyDirectoryFilter(entry)) { - return false; - } - if (this.isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { - return false; - } - return this.isMatchToPatterns(entry.path, positiveRe) && !this.isMatchToPatterns(entry.path, negativeRe); - }; - /** - * Return true if the entry already has in the cross reader index. - */ - EntryFilter.prototype.isDuplicateEntry = function (entry) { - return this.index.has(entry.path); - }; - /** - * Create record in the cross reader index. - */ - EntryFilter.prototype.createIndexRecord = function (entry) { - this.index.set(entry.path, undefined); - }; - /** - * Returns true for non-files if the «onlyFiles» option is enabled. - */ - EntryFilter.prototype.onlyFileFilter = function (entry) { - return this.options.onlyFiles && !entry.isFile(); - }; - /** - * Returns true for non-directories if the «onlyDirectories» option is enabled. - */ - EntryFilter.prototype.onlyDirectoryFilter = function (entry) { - return this.options.onlyDirectories && !entry.isDirectory(); - }; - /** - * Return true when `absolute` option is enabled and matched to the negative patterns. - */ - EntryFilter.prototype.isSkippedByAbsoluteNegativePatterns = function (entry, negativeRe) { - if (!this.options.absolute) { - return false; - } - var fullpath = pathUtils.makeAbsolute(this.options.cwd, entry.path); - return this.isMatchToPatterns(fullpath, negativeRe); - }; - /** - * Return true when entry match to provided patterns. - * - * First, just trying to apply patterns to the path. - * Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns). - */ - EntryFilter.prototype.isMatchToPatterns = function (filepath, patternsRe) { - return patternUtils.matchAny(filepath, patternsRe) || patternUtils.matchAny(filepath + '/', patternsRe); - }; - return EntryFilter; -}()); -exports.default = EntryFilter; - - -/***/ }), -/* 735 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var stream = __webpack_require__(138); -var fsStat = __webpack_require__(736); -var fs_1 = __webpack_require__(740); -var FileSystemStream = /** @class */ (function (_super) { - __extends(FileSystemStream, _super); - function FileSystemStream() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * Use stream API to read entries for Task. - */ - FileSystemStream.prototype.read = function (patterns, filter) { - var _this = this; - var filepaths = patterns.map(this.getFullEntryPath, this); - var transform = new stream.Transform({ objectMode: true }); - transform._transform = function (index, _enc, done) { - return _this.getEntry(filepaths[index], patterns[index]).then(function (entry) { - if (entry !== null && filter(entry)) { - transform.push(entry); - } - if (index === filepaths.length - 1) { - transform.end(); - } - done(); - }); - }; - for (var i = 0; i < filepaths.length; i++) { - transform.write(i); - } - return transform; - }; - /** - * Return entry for the provided path. - */ - FileSystemStream.prototype.getEntry = function (filepath, pattern) { - var _this = this; - return this.getStat(filepath) - .then(function (stat) { return _this.makeEntry(stat, pattern); }) - .catch(function () { return null; }); - }; - /** - * Return fs.Stats for the provided path. - */ - FileSystemStream.prototype.getStat = function (filepath) { - return fsStat.stat(filepath, { throwErrorOnBrokenSymlinks: false }); - }; - return FileSystemStream; -}(fs_1.default)); -exports.default = FileSystemStream; - - -/***/ }), -/* 736 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(737); -const statProvider = __webpack_require__(739); -/** - * Asynchronous API. - */ -function stat(path, opts) { - return new Promise((resolve, reject) => { - statProvider.async(path, optionsManager.prepare(opts), (err, stats) => err ? reject(err) : resolve(stats)); - }); -} -exports.stat = stat; -function statCallback(path, optsOrCallback, callback) { - if (typeof optsOrCallback === 'function') { - callback = optsOrCallback; /* tslint:disable-line: no-parameter-reassignment */ - optsOrCallback = undefined; /* tslint:disable-line: no-parameter-reassignment */ - } - if (typeof callback === 'undefined') { - throw new TypeError('The "callback" argument must be of type Function.'); - } - statProvider.async(path, optionsManager.prepare(optsOrCallback), callback); -} -exports.statCallback = statCallback; -/** - * Synchronous API. - */ -function statSync(path, opts) { - return statProvider.sync(path, optionsManager.prepare(opts)); -} -exports.statSync = statSync; - - -/***/ }), -/* 737 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(738); -function prepare(opts) { - const options = Object.assign({ - fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), - throwErrorOnBrokenSymlinks: true, - followSymlinks: true - }, opts); - return options; -} -exports.prepare = prepare; - - -/***/ }), -/* 738 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(134); -exports.FILE_SYSTEM_ADAPTER = { - lstat: fs.lstat, - stat: fs.stat, - lstatSync: fs.lstatSync, - statSync: fs.statSync -}; -function getFileSystemAdapter(fsMethods) { - if (!fsMethods) { - return exports.FILE_SYSTEM_ADAPTER; - } - return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); -} -exports.getFileSystemAdapter = getFileSystemAdapter; - - -/***/ }), -/* 739 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function sync(path, options) { - const lstat = options.fs.lstatSync(path); - if (!isFollowedSymlink(lstat, options)) { - return lstat; - } - try { - const stat = options.fs.statSync(path); - stat.isSymbolicLink = () => true; - return stat; - } - catch (err) { - if (!options.throwErrorOnBrokenSymlinks) { - return lstat; - } - throw err; - } -} -exports.sync = sync; -function async(path, options, callback) { - options.fs.lstat(path, (err0, lstat) => { - if (err0) { - return callback(err0, undefined); - } - if (!isFollowedSymlink(lstat, options)) { - return callback(null, lstat); - } - options.fs.stat(path, (err1, stat) => { - if (err1) { - return options.throwErrorOnBrokenSymlinks ? callback(err1) : callback(null, lstat); - } - stat.isSymbolicLink = () => true; - callback(null, stat); - }); - }); -} -exports.async = async; -/** - * Returns `true` for followed symlink. - */ -function isFollowedSymlink(stat, options) { - return stat.isSymbolicLink() && options.followSymlinks; -} -exports.isFollowedSymlink = isFollowedSymlink; - - -/***/ }), -/* 740 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(4); -var FileSystem = /** @class */ (function () { - function FileSystem(options) { - this.options = options; - } - /** - * Return full path to entry. - */ - FileSystem.prototype.getFullEntryPath = function (filepath) { - return path.resolve(this.options.cwd, filepath); - }; - /** - * Return an implementation of the Entry interface. - */ - FileSystem.prototype.makeEntry = function (stat, pattern) { - stat.path = pattern; - stat.depth = pattern.split('/').length; - return stat; - }; - return FileSystem; -}()); -exports.default = FileSystem; - - -/***/ }), -/* 741 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var stream = __webpack_require__(138); -var readdir = __webpack_require__(718); -var reader_1 = __webpack_require__(731); -var fs_stream_1 = __webpack_require__(735); -var TransformStream = /** @class */ (function (_super) { - __extends(TransformStream, _super); - function TransformStream(reader) { - var _this = _super.call(this, { objectMode: true }) || this; - _this.reader = reader; - return _this; - } - TransformStream.prototype._transform = function (entry, _encoding, callback) { - callback(null, this.reader.transform(entry)); - }; - return TransformStream; -}(stream.Transform)); -var ReaderStream = /** @class */ (function (_super) { - __extends(ReaderStream, _super); - function ReaderStream() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderStream.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_stream_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use stream API to read entries for Task. - */ - ReaderStream.prototype.read = function (task) { - var _this = this; - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - var transform = new TransformStream(this); - var readable = this.api(root, task, options); - return readable - .on('error', function (err) { return _this.isEnoentCodeError(err) ? null : transform.emit('error', err); }) - .pipe(transform); - }; - /** - * Returns founded paths. - */ - ReaderStream.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderStream.prototype.dynamicApi = function (root, options) { - return readdir.readdirStreamStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderStream.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderStream; -}(reader_1.default)); -exports.default = ReaderStream; - - -/***/ }), -/* 742 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(718); -var reader_1 = __webpack_require__(731); -var fs_sync_1 = __webpack_require__(743); -var ReaderSync = /** @class */ (function (_super) { - __extends(ReaderSync, _super); - function ReaderSync() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderSync.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_sync_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use sync API to read entries for Task. - */ - ReaderSync.prototype.read = function (task) { - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - try { - var entries = this.api(root, task, options); - return entries.map(this.transform, this); - } - catch (err) { - if (this.isEnoentCodeError(err)) { - return []; - } - throw err; - } - }; - /** - * Returns founded paths. - */ - ReaderSync.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderSync.prototype.dynamicApi = function (root, options) { - return readdir.readdirSyncStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderSync.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderSync; -}(reader_1.default)); -exports.default = ReaderSync; - - -/***/ }), -/* 743 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(736); -var fs_1 = __webpack_require__(740); -var FileSystemSync = /** @class */ (function (_super) { - __extends(FileSystemSync, _super); - function FileSystemSync() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * Use sync API to read entries for Task. - */ - FileSystemSync.prototype.read = function (patterns, filter) { - var _this = this; - var entries = []; - patterns.forEach(function (pattern) { - var filepath = _this.getFullEntryPath(pattern); - var entry = _this.getEntry(filepath, pattern); - if (entry === null || !filter(entry)) { - return; - } - entries.push(entry); - }); - return entries; - }; - /** - * Return entry for the provided path. - */ - FileSystemSync.prototype.getEntry = function (filepath, pattern) { - try { - var stat = this.getStat(filepath); - return this.makeEntry(stat, pattern); - } - catch (err) { - return null; - } - }; - /** - * Return fs.Stats for the provided path. - */ - FileSystemSync.prototype.getStat = function (filepath) { - return fsStat.statSync(filepath, { throwErrorOnBrokenSymlinks: false }); - }; - return FileSystemSync; -}(fs_1.default)); -exports.default = FileSystemSync; - - -/***/ }), -/* 744 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -/** - * Flatten nested arrays (max depth is 2) into a non-nested array of non-array items. - */ -function flatten(items) { - return items.reduce(function (collection, item) { return [].concat(collection, item); }, []); -} -exports.flatten = flatten; - - -/***/ }), -/* 745 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(354); -/** - * Merge multiple streams and propagate their errors into one stream in parallel. - */ -function merge(streams) { - var mergedStream = merge2(streams); - streams.forEach(function (stream) { - stream.on('error', function (err) { return mergedStream.emit('error', err); }); - }); - return mergedStream; -} -exports.merge = merge; - - -/***/ }), -/* 746 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(4); -const pathType = __webpack_require__(747); - -const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; - -const getPath = (filepath, cwd) => { - const pth = filepath[0] === '!' ? filepath.slice(1) : filepath; - return path.isAbsolute(pth) ? pth : path.join(cwd, pth); -}; - -const addExtensions = (file, extensions) => { - if (path.extname(file)) { - return `**/${file}`; - } - - return `**/${file}.${getExtensions(extensions)}`; -}; - -const getGlob = (dir, opts) => { - if (opts.files && !Array.isArray(opts.files)) { - throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof opts.files}\``); - } - - if (opts.extensions && !Array.isArray(opts.extensions)) { - throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof opts.extensions}\``); - } - - if (opts.files && opts.extensions) { - return opts.files.map(x => path.join(dir, addExtensions(x, opts.extensions))); - } - - if (opts.files) { - return opts.files.map(x => path.join(dir, `**/${x}`)); - } - - if (opts.extensions) { - return [path.join(dir, `**/*.${getExtensions(opts.extensions)}`)]; - } - - return [path.join(dir, '**')]; -}; - -module.exports = (input, opts) => { - opts = Object.assign({cwd: process.cwd()}, opts); - - if (typeof opts.cwd !== 'string') { - return Promise.reject(new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``)); - } - - return Promise.all([].concat(input).map(x => pathType.dir(getPath(x, opts.cwd)) - .then(isDir => isDir ? getGlob(x, opts) : x))) - .then(globs => [].concat.apply([], globs)); -}; - -module.exports.sync = (input, opts) => { - opts = Object.assign({cwd: process.cwd()}, opts); - - if (typeof opts.cwd !== 'string') { - throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``); - } - - const globs = [].concat(input).map(x => pathType.dirSync(getPath(x, opts.cwd)) ? getGlob(x, opts) : x); - return [].concat.apply([], globs); -}; - - -/***/ }), -/* 747 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const fs = __webpack_require__(134); -const pify = __webpack_require__(748); - -function type(fn, fn2, fp) { - if (typeof fp !== 'string') { - return Promise.reject(new TypeError(`Expected a string, got ${typeof fp}`)); - } - - return pify(fs[fn])(fp) - .then(stats => stats[fn2]()) - .catch(err => { - if (err.code === 'ENOENT') { - return false; - } - - throw err; - }); -} - -function typeSync(fn, fn2, fp) { - if (typeof fp !== 'string') { - throw new TypeError(`Expected a string, got ${typeof fp}`); - } - - try { - return fs[fn](fp)[fn2](); - } catch (err) { - if (err.code === 'ENOENT') { - return false; - } - - throw err; - } -} - -exports.file = type.bind(null, 'stat', 'isFile'); -exports.dir = type.bind(null, 'stat', 'isDirectory'); -exports.symlink = type.bind(null, 'lstat', 'isSymbolicLink'); -exports.fileSync = typeSync.bind(null, 'statSync', 'isFile'); -exports.dirSync = typeSync.bind(null, 'statSync', 'isDirectory'); -exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); - - -/***/ }), -/* 748 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); - - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } - - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } - - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); - } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } - - resolve(results); - } else { - resolve(result); - } - }); - } - - fn.apply(this, args); - }); -}; - -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); - - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); - }; - - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } - - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; - } - - return ret; -}; - - -/***/ }), -/* 749 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const fs = __webpack_require__(134); -const path = __webpack_require__(4); -const fastGlob = __webpack_require__(575); -const gitIgnore = __webpack_require__(750); -const pify = __webpack_require__(285); -const slash = __webpack_require__(751); - -const DEFAULT_IGNORE = [ - '**/node_modules/**', - '**/bower_components/**', - '**/flow-typed/**', - '**/coverage/**', - '**/.git' -]; - -const readFileP = pify(fs.readFile); - -const mapGitIgnorePatternTo = base => ignore => { - if (ignore.startsWith('!')) { - return '!' + path.posix.join(base, ignore.slice(1)); - } - - return path.posix.join(base, ignore); -}; - -const parseGitIgnore = (content, options) => { - const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); - - return content - .split(/\r?\n/) - .filter(Boolean) - .filter(line => line.charAt(0) !== '#') - .map(mapGitIgnorePatternTo(base)); -}; - -const reduceIgnore = files => { - return files.reduce((ignores, file) => { - ignores.add(parseGitIgnore(file.content, { - cwd: file.cwd, - fileName: file.filePath - })); - return ignores; - }, gitIgnore()); -}; - -const getIsIgnoredPredecate = (ignores, cwd) => { - return p => ignores.ignores(slash(path.relative(cwd, p))); -}; - -const getFile = (file, cwd) => { - const filePath = path.join(cwd, file); - return readFileP(filePath, 'utf8') - .then(content => ({ - content, - cwd, - filePath - })); -}; - -const getFileSync = (file, cwd) => { - const filePath = path.join(cwd, file); - const content = fs.readFileSync(filePath, 'utf8'); - - return { - content, - cwd, - filePath - }; -}; - -const normalizeOptions = (options = {}) => { - const ignore = options.ignore || []; - const cwd = options.cwd || process.cwd(); - return {ignore, cwd}; -}; - -module.exports = options => { - options = normalizeOptions(options); - - return fastGlob('**/.gitignore', { - ignore: DEFAULT_IGNORE.concat(options.ignore), - cwd: options.cwd - }) - .then(paths => Promise.all(paths.map(file => getFile(file, options.cwd)))) - .then(files => reduceIgnore(files)) - .then(ignores => getIsIgnoredPredecate(ignores, options.cwd)); -}; - -module.exports.sync = options => { - options = normalizeOptions(options); - - const paths = fastGlob.sync('**/.gitignore', { - ignore: DEFAULT_IGNORE.concat(options.ignore), - cwd: options.cwd - }); - const files = paths.map(file => getFileSync(file, options.cwd)); - const ignores = reduceIgnore(files); - - return getIsIgnoredPredecate(ignores, options.cwd); -}; - - -/***/ }), -/* 750 */ -/***/ (function(module, exports) { - -// A simple implementation of make-array -function make_array (subject) { - return Array.isArray(subject) - ? subject - : [subject] -} - -const REGEX_BLANK_LINE = /^\s+$/ -const REGEX_LEADING_EXCAPED_EXCLAMATION = /^\\!/ -const REGEX_LEADING_EXCAPED_HASH = /^\\#/ -const SLASH = '/' -const KEY_IGNORE = typeof Symbol !== 'undefined' - ? Symbol.for('node-ignore') - /* istanbul ignore next */ - : 'node-ignore' - -const define = (object, key, value) => - Object.defineProperty(object, key, {value}) - -const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g - -// Sanitize the range of a regular expression -// The cases are complicated, see test cases for details -const sanitizeRange = range => range.replace( - REGEX_REGEXP_RANGE, - (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) - ? match - // Invalid range (out of order) which is ok for gitignore rules but - // fatal for JavaScript regular expression, so eliminate it. - : '' -) - -// > If the pattern ends with a slash, -// > it is removed for the purpose of the following description, -// > but it would only find a match with a directory. -// > In other words, foo/ will match a directory foo and paths underneath it, -// > but will not match a regular file or a symbolic link foo -// > (this is consistent with the way how pathspec works in general in Git). -// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`' -// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call -// you could use option `mark: true` with `glob` - -// '`foo/`' should not continue with the '`..`' -const DEFAULT_REPLACER_PREFIX = [ - - // > Trailing spaces are ignored unless they are quoted with backslash ("\") - [ - // (a\ ) -> (a ) - // (a ) -> (a) - // (a \ ) -> (a ) - /\\?\s+$/, - match => match.indexOf('\\') === 0 - ? ' ' - : '' - ], - - // replace (\ ) with ' ' - [ - /\\\s/g, - () => ' ' - ], - - // Escape metacharacters - // which is written down by users but means special for regular expressions. - - // > There are 12 characters with special meanings: - // > - the backslash \, - // > - the caret ^, - // > - the dollar sign $, - // > - the period or dot ., - // > - the vertical bar or pipe symbol |, - // > - the question mark ?, - // > - the asterisk or star *, - // > - the plus sign +, - // > - the opening parenthesis (, - // > - the closing parenthesis ), - // > - and the opening square bracket [, - // > - the opening curly brace {, - // > These special characters are often called "metacharacters". - [ - /[\\^$.|*+(){]/g, - match => `\\${match}` - ], - - [ - // > [abc] matches any character inside the brackets - // > (in this case a, b, or c); - /\[([^\]/]*)($|\])/g, - (match, p1, p2) => p2 === ']' - ? `[${sanitizeRange(p1)}]` - : `\\${match}` - ], - - [ - // > a question mark (?) matches a single character - /(?!\\)\?/g, - () => '[^/]' - ], - - // leading slash - [ - - // > A leading slash matches the beginning of the pathname. - // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". - // A leading slash matches the beginning of the pathname - /^\//, - () => '^' - ], - - // replace special metacharacter slash after the leading slash - [ - /\//g, - () => '\\/' - ], - - [ - // > A leading "**" followed by a slash means match in all directories. - // > For example, "**/foo" matches file or directory "foo" anywhere, - // > the same as pattern "foo". - // > "**/foo/bar" matches file or directory "bar" anywhere that is directly - // > under directory "foo". - // Notice that the '*'s have been replaced as '\\*' - /^\^*\\\*\\\*\\\//, - - // '**/foo' <-> 'foo' - () => '^(?:.*\\/)?' - ] -] - -const DEFAULT_REPLACER_SUFFIX = [ - // starting - [ - // there will be no leading '/' - // (which has been replaced by section "leading slash") - // If starts with '**', adding a '^' to the regular expression also works - /^(?=[^^])/, - function startingReplacer () { - return !/\/(?!$)/.test(this) - // > If the pattern does not contain a slash /, - // > Git treats it as a shell glob pattern - // Actually, if there is only a trailing slash, - // git also treats it as a shell glob pattern - ? '(?:^|\\/)' - - // > Otherwise, Git treats the pattern as a shell glob suitable for - // > consumption by fnmatch(3) - : '^' - } - ], - - // two globstars - [ - // Use lookahead assertions so that we could match more than one `'/**'` - /\\\/\\\*\\\*(?=\\\/|$)/g, - - // Zero, one or several directories - // should not use '*', or it will be replaced by the next replacer - - // Check if it is not the last `'/**'` - (match, index, str) => index + 6 < str.length - - // case: /**/ - // > A slash followed by two consecutive asterisks then a slash matches - // > zero or more directories. - // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on. - // '/**/' - ? '(?:\\/[^\\/]+)*' - - // case: /** - // > A trailing `"/**"` matches everything inside. - - // #21: everything inside but it should not include the current folder - : '\\/.+' - ], - - // intermediate wildcards - [ - // Never replace escaped '*' - // ignore rule '\*' will match the path '*' - - // 'abc.*/' -> go - // 'abc.*' -> skip this rule - /(^|[^\\]+)\\\*(?=.+)/g, - - // '*.js' matches '.js' - // '*.js' doesn't match 'abc' - (match, p1) => `${p1}[^\\/]*` - ], - - // trailing wildcard - [ - /(\^|\\\/)?\\\*$/, - (match, p1) => { - const prefix = p1 - // '\^': - // '/*' does not match '' - // '/*' does not match everything - - // '\\\/': - // 'abc/*' does not match 'abc/' - ? `${p1}[^/]+` - - // 'a*' matches 'a' - // 'a*' matches 'aa' - : '[^/]*' - - return `${prefix}(?=$|\\/$)` - } - ], - - [ - // unescape - /\\\\\\/g, - () => '\\' - ] -] - -const POSITIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, - - // 'f' - // matches - // - /f(end) - // - /f/ - // - (start)f(end) - // - (start)f/ - // doesn't match - // - oof - // - foo - // pseudo: - // -> (^|/)f(/|$) - - // ending - [ - // 'js' will not match 'js.' - // 'ab' will not match 'abc' - /(?:[^*/])$/, - - // 'js*' will not match 'a.js' - // 'js/' will not match 'a.js' - // 'js' will match 'a.js' and 'a.js/' - match => `${match}(?=$|\\/)` - ], - - ...DEFAULT_REPLACER_SUFFIX -] - -const NEGATIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, - - // #24, #38 - // The MISSING rule of [gitignore docs](https://git-scm.com/docs/gitignore) - // A negative pattern without a trailing wildcard should not - // re-include the things inside that directory. - - // eg: - // ['node_modules/*', '!node_modules'] - // should ignore `node_modules/a.js` - [ - /(?:[^*])$/, - match => `${match}(?=$|\\/$)` - ], - - ...DEFAULT_REPLACER_SUFFIX -] - -// A simple cache, because an ignore rule only has only one certain meaning -const cache = Object.create(null) - -// @param {pattern} -const make_regex = (pattern, negative, ignorecase) => { - const r = cache[pattern] - if (r) { - return r - } - - const replacers = negative - ? NEGATIVE_REPLACERS - : POSITIVE_REPLACERS - - const source = replacers.reduce( - (prev, current) => prev.replace(current[0], current[1].bind(pattern)), - pattern - ) - - return cache[pattern] = ignorecase - ? new RegExp(source, 'i') - : new RegExp(source) -} - -// > A blank line matches no files, so it can serve as a separator for readability. -const checkPattern = pattern => pattern - && typeof pattern === 'string' - && !REGEX_BLANK_LINE.test(pattern) - - // > A line starting with # serves as a comment. - && pattern.indexOf('#') !== 0 - -const createRule = (pattern, ignorecase) => { - const origin = pattern - let negative = false - - // > An optional prefix "!" which negates the pattern; - if (pattern.indexOf('!') === 0) { - negative = true - pattern = pattern.substr(1) - } - - pattern = pattern - // > Put a backslash ("\") in front of the first "!" for patterns that - // > begin with a literal "!", for example, `"\!important!.txt"`. - .replace(REGEX_LEADING_EXCAPED_EXCLAMATION, '!') - // > Put a backslash ("\") in front of the first hash for patterns that - // > begin with a hash. - .replace(REGEX_LEADING_EXCAPED_HASH, '#') - - const regex = make_regex(pattern, negative, ignorecase) - - return { - origin, - pattern, - negative, - regex - } -} - -class IgnoreBase { - constructor ({ - ignorecase = true - } = {}) { - this._rules = [] - this._ignorecase = ignorecase - define(this, KEY_IGNORE, true) - this._initCache() - } - - _initCache () { - this._cache = Object.create(null) - } - - // @param {Array.|string|Ignore} pattern - add (pattern) { - this._added = false - - if (typeof pattern === 'string') { - pattern = pattern.split(/\r?\n/g) - } - - make_array(pattern).forEach(this._addPattern, this) - - // Some rules have just added to the ignore, - // making the behavior changed. - if (this._added) { - this._initCache() - } - - return this - } - - // legacy - addPattern (pattern) { - return this.add(pattern) - } - - _addPattern (pattern) { - // #32 - if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat(pattern._rules) - this._added = true - return - } - - if (checkPattern(pattern)) { - const rule = createRule(pattern, this._ignorecase) - this._added = true - this._rules.push(rule) - } - } - - filter (paths) { - return make_array(paths).filter(path => this._filter(path)) - } - - createFilter () { - return path => this._filter(path) - } - - ignores (path) { - return !this._filter(path) - } - - // @returns `Boolean` true if the `path` is NOT ignored - _filter (path, slices) { - if (!path) { - return false - } - - if (path in this._cache) { - return this._cache[path] - } - - if (!slices) { - // path/to/a.js - // ['path', 'to', 'a.js'] - slices = path.split(SLASH) - } - - slices.pop() - - return this._cache[path] = slices.length - // > It is not possible to re-include a file if a parent directory of - // > that file is excluded. - // If the path contains a parent directory, check the parent first - ? this._filter(slices.join(SLASH) + SLASH, slices) - && this._test(path) - - // Or only test the path - : this._test(path) - } - - // @returns {Boolean} true if a file is NOT ignored - _test (path) { - // Explicitly define variable type by setting matched to `0` - let matched = 0 - - this._rules.forEach(rule => { - // if matched = true, then we only test negative rules - // if matched = false, then we test non-negative rules - if (!(matched ^ rule.negative)) { - matched = rule.negative ^ rule.regex.test(path) - } - }) - - return !matched - } -} - -// Windows -// -------------------------------------------------------------- -/* istanbul ignore if */ -if ( - // Detect `process` so that it can run in browsers. - typeof process !== 'undefined' - && ( - process.env && process.env.IGNORE_TEST_WIN32 - || process.platform === 'win32' - ) -) { - const filter = IgnoreBase.prototype._filter +class FilterStream extends ObjectTransform { + constructor(filter) { + super(); + this._filter = filter; + } - /* eslint no-control-regex: "off" */ - const make_posix = str => /^\\\\\?\\/.test(str) - || /[^\x00-\x80]+/.test(str) - ? str - : str.replace(/\\/g, '/') + _transform(data, encoding, callback) { + if (this._filter(data)) { + this.push(data); + } - IgnoreBase.prototype._filter = function filterWin32 (path, slices) { - path = make_posix(path) - return filter.call(this, path, slices) - } + callback(); + } } -module.exports = options => new IgnoreBase(options) - - -/***/ }), -/* 751 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +class UniqueStream extends ObjectTransform { + constructor() { + super(); + this._pushed = new Set(); + } -module.exports = input => { - const isExtendedLengthPath = /^\\\\\?\\/.test(input); - const hasNonAscii = /[^\u0000-\u0080]+/.test(input); // eslint-disable-line no-control-regex + _transform(data, encoding, callback) { + if (!this._pushed.has(data)) { + this.push(data); + this._pushed.add(data); + } - if (isExtendedLengthPath || hasNonAscii) { - return input; + callback(); } +} - return input.replace(/\\/g, '/'); +module.exports = { + FilterStream, + UniqueStream }; /***/ }), -/* 752 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83197,7 +59778,7 @@ module.exports = input => { -var isGlob = __webpack_require__(753); +var isGlob = __webpack_require__(576); module.exports = function hasGlob(val) { if (val == null) return false; @@ -83217,7 +59798,7 @@ module.exports = function hasGlob(val) { /***/ }), -/* 753 */ +/* 576 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -83248,17 +59829,17 @@ module.exports = function isGlob(str) { /***/ }), -/* 754 */ +/* 577 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const {constants: fsConstants} = __webpack_require__(134); -const pEvent = __webpack_require__(755); -const CpFileError = __webpack_require__(758); -const fs = __webpack_require__(760); -const ProgressEmitter = __webpack_require__(762); +const pEvent = __webpack_require__(578); +const CpFileError = __webpack_require__(581); +const fs = __webpack_require__(583); +const ProgressEmitter = __webpack_require__(585); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -83372,12 +59953,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 755 */ +/* 578 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(756); +const pTimeout = __webpack_require__(579); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -83670,13 +60251,13 @@ module.exports.TimeoutError = pTimeout.TimeoutError; /***/ }), -/* 756 */ +/* 579 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(757); +const pFinally = __webpack_require__(580); class TimeoutError extends Error { constructor(message) { @@ -83734,7 +60315,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 757 */ +/* 580 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83756,12 +60337,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 758 */ +/* 581 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(759); +const NestedError = __webpack_require__(582); class CpFileError extends NestedError { constructor(message, nested) { @@ -83775,7 +60356,7 @@ module.exports = CpFileError; /***/ }), -/* 759 */ +/* 582 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(112).inherits; @@ -83831,16 +60412,16 @@ module.exports = NestedError; /***/ }), -/* 760 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(112); const fs = __webpack_require__(133); -const makeDir = __webpack_require__(761); -const pEvent = __webpack_require__(755); -const CpFileError = __webpack_require__(758); +const makeDir = __webpack_require__(584); +const pEvent = __webpack_require__(578); +const CpFileError = __webpack_require__(581); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -83937,7 +60518,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 761 */ +/* 584 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84100,7 +60681,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 762 */ +/* 585 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84141,7 +60722,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 763 */ +/* 586 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84187,12 +60768,12 @@ exports.default = module.exports; /***/ }), -/* 764 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(765); +const pMap = __webpack_require__(588); const pFilter = async (iterable, filterer, options) => { const values = await pMap( @@ -84209,7 +60790,7 @@ module.exports.default = pFilter; /***/ }), -/* 765 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84288,12 +60869,12 @@ module.exports.default = pMap; /***/ }), -/* 766 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(759); +const NestedError = __webpack_require__(582); class CpyError extends NestedError { constructor(message, nested) { diff --git a/packages/osd-pm/package.json b/packages/osd-pm/package.json index f6c25309e992..226264b828e3 100644 --- a/packages/osd-pm/package.json +++ b/packages/osd-pm/package.json @@ -23,7 +23,6 @@ "@types/dedent": "^0.7.0", "@types/getopts": "^2.0.1", "@types/glob": "^7.1.3", - "@types/globby": "^8.0.0", "@types/has-ansi": "^3.0.0", "@types/lodash": "^4.14.170", "@types/log-symbols": "^2.0.0", @@ -62,7 +61,7 @@ "tempy": "^0.3.0", "typescript": "4.0.2", "unlazy-loader": "^0.1.3", - "webpack": "npm:@amoo-miki/webpack@4.46.0-rc.2", + "webpack": "npm:@amoo-miki/webpack@4.46.0-xxhash.1", "webpack-cli": "^4.9.2", "write-pkg": "^4.0.0" }, diff --git a/packages/osd-pm/src/production/build_production_projects.ts b/packages/osd-pm/src/production/build_production_projects.ts index 534166716f49..3949968da396 100644 --- a/packages/osd-pm/src/production/build_production_projects.ts +++ b/packages/osd-pm/src/production/build_production_projects.ts @@ -130,7 +130,6 @@ async function copyToBuild(project: Project, opensearchDashboardsRoot: string, b await copy(['**/*', '!node_modules/**'], buildProjectPath, { cwd: project.getIntermediateBuildDirectory(), dot: true, - nodir: true, parents: true, }); diff --git a/packages/osd-ui-shared-deps/package.json b/packages/osd-ui-shared-deps/package.json index 8f7777459b01..bc1a256a9bc9 100644 --- a/packages/osd-ui-shared-deps/package.json +++ b/packages/osd-ui-shared-deps/package.json @@ -49,6 +49,6 @@ "sass-embedded": "1.66.1", "sass-loader": "npm:@amoo-miki/sass-loader@10.4.1-node-sass-9.0.0-libsass-3.6.5-with-sass-embedded.rc1", "val-loader": "^2.1.2", - "webpack": "npm:@amoo-miki/webpack@4.46.0-rc.2" + "webpack": "npm:@amoo-miki/webpack@4.46.0-xxhash.1" } } diff --git a/yarn.lock b/yarn.lock index 16143fcd97ac..d6084909cf0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2361,14 +2361,6 @@ resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz#3b0efb6d3903bd49edb073696f60e90df08efb26" integrity sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg== -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - "@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz#44d752c1a2dc113f15f781b7cc4f53a307e3fa38" @@ -2501,11 +2493,6 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - "@nodelib/fs.walk@^1.2.3": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" @@ -3139,14 +3126,6 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/globby@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@types/globby/-/globby-8.0.0.tgz#7bd10eaf802e1e11afdb1e5436cf472ddf4c0dd2" - integrity sha512-xDtsX5tlctxJzvg29r/LN12z30oJpoFP9cE8eJ8nY5cbSvN0c0RdRHrVlEq4LRh362Sd+JsqxJ3QWw0Wnyto8w== - dependencies: - "@types/glob" "*" - fast-glob "^2.0.2" - "@types/graceful-fs@*", "@types/graceful-fs@^4.1.2": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -3892,14 +3871,13 @@ "@types/expect" "^1.20.4" "@types/node" "*" -"@types/watchpack@^1.1.6": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@types/watchpack/-/watchpack-1.1.7.tgz#9e680b223294cdfc10cb5a04da0543a97023cdd7" - integrity sha512-2XsUDmKGy5ymzQ48ev61nMimudAiZEH/qEBo9zueKA45F8OXIAD2iwEFZPi+uCHnsxcV5MMnbu+Hkx0CLgfTxw== +"@types/watchpack@^2.4.4": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/watchpack/-/watchpack-2.4.4.tgz#d492bca62ba73cf041eda26e494fe7a540852836" + integrity sha512-SbuSavsPxfOPZwVHBgQUVuzYBe6+8KL7dwiJLXaj5rmv3DxktOMwX5WP1J6UontwUbewjVoc7pCgZvqy6rPn+A== dependencies: "@types/graceful-fs" "*" "@types/node" "*" - chokidar "^2.1.2" "@types/webpack-env@^1.16.3": version "1.16.3" @@ -4492,14 +4470,6 @@ any-observable@^0.3.0: resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - 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" @@ -4598,11 +4568,6 @@ arr-diff@^4.0.0: resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" @@ -4652,7 +4617,7 @@ array-slice@^1.0.0: resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== -array-union@^1.0.1, array-union@^1.0.2: +array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= @@ -4669,11 +4634,6 @@ array-uniq@^1.0.1: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - array.prototype.every@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/array.prototype.every/-/array.prototype.every-1.1.3.tgz#31f01b48e1160bc4b49ecab246bf7f765c6686f9" @@ -4801,11 +4761,6 @@ async-cache@^1.1.0: dependencies: lru-cache "^4.0.0" -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - async-value-promise@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/async-value-promise/-/async-value-promise-1.1.1.tgz#68957819e3eace804f3b4b69477e2bd276c15378" @@ -5089,19 +5044,6 @@ base64url@^3.0.1: resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - basic-auth@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" @@ -5119,11 +5061,6 @@ big.js@^5.2.2: resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -5134,13 +5071,6 @@ binary-search@^1.3.3: resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.6.tgz#e32426016a0c5092f0f3598836a1c7da3560565c" integrity sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA== -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - bl@^4.0.3: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -5193,28 +5123,12 @@ brace@0.11.1, brace@^0.11.1: resolved "https://registry.yarnpkg.com/brace/-/brace-0.11.1.tgz#4896fcc9d544eef45f4bb7660db320d3b379fe58" integrity sha1-SJb8ydVE7vRfS7dmDbMg07N5/lg= -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" breadth-filter@^2.0.0: version "2.0.0" @@ -5445,21 +5359,6 @@ cacache@^15.0.5: tar "^6.0.2" unique-filename "^1.1.1" -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" @@ -5497,11 +5396,6 @@ call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: get-intrinsic "^1.2.1" set-function-length "^1.1.1" -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -5668,7 +5562,7 @@ cheerio@^1.0.0-rc.3: parse5-htmlparser2-tree-adapter "^6.0.1" tslib "^2.2.0" -chokidar@3.5.3, chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2: +chokidar@3.5.3, chokidar@^2.1.8, chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -5683,25 +5577,6 @@ chokidar@3.5.3, chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.4.2: optionalDependencies: fsevents "~2.3.2" -chokidar@^2.1.2, chokidar@^2.1.8: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - chownr@^1.1.1, chownr@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" @@ -5753,16 +5628,6 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - classnames@2.3.1, classnames@2.x, classnames@^2.2.5, classnames@^2.2.6: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" @@ -5935,14 +5800,6 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - color-convert@^1.8.2, color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -6067,7 +5924,7 @@ complex.js@^2.1.1: resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.1.1.tgz#0675dac8e464ec431fb2ab7d30f41d889fb25c31" integrity sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg== -component-emitter@^1.2.1, component-emitter@^1.3.0: +component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -6172,11 +6029,6 @@ copy-concurrently@^1.0.0: rimraf "^2.5.4" run-queue "^1.0.0" -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - copy-to-clipboard@^3.2.0: version "3.3.1" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" @@ -6794,7 +6646,7 @@ debug@4.3.1: dependencies: ms "2.1.2" -debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: +debug@^2.2.0, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -6926,28 +6778,6 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -7127,13 +6957,6 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" -dir-glob@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - dependencies: - path-type "^3.0.0" - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -8239,19 +8062,6 @@ exit@^0.1.2, exit@~0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" @@ -8281,14 +8091,7 @@ ext@^1.1.2: dependencies: type "^2.5.0" -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: +extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= @@ -8310,20 +8113,6 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - extract-opts@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/extract-opts/-/extract-opts-4.3.0.tgz#ee0a797249abb77e449bdaaba66ebeff4775505e" @@ -8353,18 +8142,6 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== -fast-glob@^2.0.2, fast-glob@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - fast-glob@^3.0.3, fast-glob@^3.2.11, fast-glob@^3.2.4, fast-glob@^3.2.9: version "3.2.11" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" @@ -8527,11 +8304,6 @@ file-type@^9.0.0: resolved "https://registry.yarnpkg.com/file-type/-/file-type-9.0.0.tgz#a68d5ad07f486414dfb2c8866f73161946714a18" integrity sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw== -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - filelist@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b" @@ -8539,20 +8311,10 @@ filelist@^1.0.1: dependencies: minimatch "^3.0.4" -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -8716,7 +8478,7 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" -for-in@^1.0.1, for-in@^1.0.2: +for-in@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= @@ -8784,13 +8546,6 @@ fraction.js@4.3.4, fraction.js@^4.2.0: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.4.tgz#b2bac8249a610c3396106da97c5a71da75b94b1c" integrity sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q== -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - from2@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" @@ -8853,14 +8608,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" @@ -8962,11 +8709,6 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - get-value@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" @@ -9035,11 +8777,6 @@ glob-stream@^6.1.0: to-absolute-glob "^2.0.0" unique-stream "^2.0.2" -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - glob-to-regexp@^0.4.0, glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" @@ -9143,7 +8880,7 @@ globalthis@^1.0.3: dependencies: define-properties "^1.1.3" -globby@^10.0.1: +globby@^10.0.1, globby@^9.2.0: version "10.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== @@ -9180,20 +8917,6 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" -globby@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" - integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^1.0.2" - dir-glob "^2.2.2" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.0.0" - globjoin@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" @@ -9469,15 +9192,6 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - has-value@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658" @@ -9486,14 +9200,6 @@ has-value@^2.0.2: get-value "^3.0.0" has-values "^2.0.1" -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - has-values@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d" @@ -9920,7 +9626,7 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore@^4.0.3, ignore@^4.0.6: +ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== @@ -10175,20 +9881,6 @@ is-absolute@^1.0.0: is-relative "^1.0.0" is-windows "^1.0.1" -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - is-alphabetical@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" @@ -10236,13 +9928,6 @@ is-bigint@^1.0.1: dependencies: has-bigints "^1.0.1" -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -10280,20 +9965,6 @@ is-core-module@^2.1.0, is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-m dependencies: hasown "^2.0.0" -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - is-date-object@^1.0.1, is-date-object@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -10306,29 +9977,6 @@ is-decimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - is-extendable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" @@ -10446,13 +10094,6 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -11507,7 +11148,7 @@ keyv@^4.0.0: dependencies: json-buffer "3.0.1" -kind-of@>=6.0.3, kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0, kind-of@^4.0.0, kind-of@^5.0.0, kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@>=6.0.3, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -12055,7 +11696,7 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-cache@^0.2.0, map-cache@^0.2.2: +map-cache@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= @@ -12070,13 +11711,6 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - mapcap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mapcap/-/mapcap-1.0.0.tgz#e8e29d04a160eaf8c92ec4bcbd2c5d07ed037e5a" @@ -12273,31 +11907,12 @@ methods@^1.1.1, methods@^1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@3.1.10, micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" miller-rabin@^4.0.0: @@ -12467,14 +12082,6 @@ mississippi@^3.0.0: stream-each "^1.1.0" through2 "^2.0.0" -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - mkdirp-classic@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" @@ -12662,11 +12269,6 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.12.1: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== - nano-css@^5.2.1: version "5.3.4" resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.4.tgz#40af6a83a76f84204f346e8ccaa9169cdae9167b" @@ -12686,23 +12288,6 @@ nanoid@3.3.3, nanoid@^3.3.1: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -13036,15 +12621,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-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - object-filter-sequence@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/object-filter-sequence/-/object-filter-sequence-1.0.0.tgz#10bb05402fff100082b80d7e83991b10db411692" @@ -13075,13 +12651,6 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - object.assign@^4.0.4, object.assign@^4.1.0, object.assign@^4.1.2, object.assign@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" @@ -13136,7 +12705,7 @@ object.map@^1.0.1: for-own "^1.0.0" make-iterator "^1.0.0" -object.pick@^1.2.0, object.pick@^1.3.0: +object.pick@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= @@ -13521,11 +13090,6 @@ parse5@^3.0.1: dependencies: "@types/node" "*" -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - path-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" @@ -13595,13 +13159,6 @@ path-to-regexp@^6.2.0: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38" integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg== -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -13658,11 +13215,6 @@ pify@^2.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -13772,11 +13324,6 @@ pngjs@^4.0.1: resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe" integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg== -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - postcss-loader@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.3.0.tgz#2c4de9657cd4f07af5ab42bd60a673004da1b8cc" @@ -14588,15 +14135,6 @@ readdir-scoped-modules@^1.0.0: graceful-fs "^4.1.2" once "^1.3.0" -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -14708,14 +14246,6 @@ regenerator-transform@^0.15.2: dependencies: "@babel/runtime" "^7.8.4" -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" @@ -14887,12 +14417,7 @@ remove-trailing-separator@^1.0.1: resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.5.4, repeat-string@^1.6.1: +repeat-string@^1.5.4: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= @@ -15227,13 +14752,6 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - safefs@^6.12.0: version "6.16.0" resolved "https://registry.yarnpkg.com/safefs/-/safefs-6.16.0.tgz#e1901c0ea1e8926289bd8d5383a65ce21bb44d2f" @@ -15461,7 +14979,7 @@ set-immediate-shim@~1.0.1: resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= -set-value@^2.0.0, set-value@^2.0.1, set-value@^4.1.0: +set-value@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/set-value/-/set-value-4.1.0.tgz#aa433662d87081b75ad88a4743bd450f044e7d09" integrity sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw== @@ -15618,36 +15136,6 @@ slide@~1.1.3: resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - sonic-boom@^1.0.2: version "1.4.1" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" @@ -15673,7 +15161,7 @@ source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: +source-map-resolve@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== @@ -15710,7 +15198,7 @@ source-map@0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= -source-map@^0.5.1, source-map@^0.5.6: +source-map@^0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -15855,13 +15343,6 @@ split-on-first@^1.0.0: resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== -split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - sprintf-js@1.1.2, sprintf-js@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" @@ -15945,14 +15426,6 @@ state-toggle@^1.0.0: resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" @@ -16758,21 +16231,6 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -16780,16 +16238,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - to-source-code@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/to-source-code/-/to-source-code-1.0.2.tgz#dd136bdb1e1dbd80bbeacf088992678e9070bfea" @@ -17197,16 +16645,6 @@ unified@^9.2.0: trough "^1.0.0" vfile "^4.0.0" -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -17340,7 +16778,7 @@ unlazy-loader@^0.1.3: dependencies: requires-regex "^0.3.3" -unset-value@^1.0.0, unset-value@^2.0.1: +unset-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-2.0.1.tgz#57bed0c22d26f28d69acde5df9a11b77c74d2df3" integrity sha512-2hvrBfjUE00PkqN+q0XP6yRAOGrR06uSiUoIQGZkc7GxvQ9H7v8quUPNtZjMg4uux69i8HWpIjLPUKwCuRGyNg== @@ -17348,11 +16786,6 @@ unset-value@^1.0.0, unset-value@^2.0.1: has-value "^2.0.2" isobject "^4.0.0" -upath@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - update-browserslist-db@^1.0.13: version "1.0.13" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" @@ -17424,11 +16857,6 @@ use-sidecar@^1.0.1, use-sidecar@^1.0.5: detect-node-es "^1.1.0" tslib "^1.9.3" -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - utif@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/utif/-/utif-2.0.1.tgz#9e1582d9bbd20011a6588548ed3266298e711759" @@ -18173,10 +17601,10 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack- source-list-map "^2.0.0" source-map "~0.6.1" -"webpack@npm:@amoo-miki/webpack@4.46.0-rc.2": - version "4.46.0-rc.2" - resolved "https://registry.yarnpkg.com/@amoo-miki/webpack/-/webpack-4.46.0-rc.2.tgz#36824597c14557a7bb0a8e13203e30275e7b02bd" - integrity sha512-Y/ZqxTHOoDF1kz3SR63Y9SZGTDUpZNNFrisTRHofWhP8QvNX3LMN+TCmEP56UfLaiLVKMcaiFjx8kFb2TgyBaQ== +"webpack@npm:@amoo-miki/webpack@4.46.0-xxhash.1": + version "4.46.0-xxhash.1" + resolved "https://registry.yarnpkg.com/@amoo-miki/webpack/-/webpack-4.46.0-xxhash.1.tgz#e8fdb0399d36715e558ad35e3ff70fd1d4ea47a7" + integrity sha512-gPwQMqfrE9326g+rZoU4BPOfcYvEcAR0XxfpV9AGUcRwl2oHoqEwq7nxSWchilpGV1i9XI7mCa8u8k4ePz6ziA== dependencies: "@node-rs/xxhash" "^1.3.0" "@webassemblyjs/ast" "1.9.0" @@ -18189,11 +17617,11 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack- chrome-trace-event "^1.0.2" enhanced-resolve "^4.5.0" eslint-scope "^4.0.3" + glob-to-regexp "^0.4.1" json-parse-better-errors "^1.0.2" loader-runner "^2.4.0" loader-utils "^2.0.4" memory-fs "^0.4.1" - micromatch "^3.1.10" mkdirp "^0.5.3" neo-async "^2.6.1" node-libs-browser "^2.2.1" From 310c2405cab88b91e7e1aa0fe1105c1a1926342d Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 7 Jun 2024 12:43:30 -0700 Subject: [PATCH 016/276] Use JSON11 for handling long numerals (#6915) (#6970) (cherry picked from commit 6a2074249c92ec204bb7edff72f93a641da1385e) Signed-off-by: Miki --- changelogs/fragments/6915.yml | 2 + package.json | 3 +- packages/osd-std/package.json | 1 + packages/osd-std/src/json.ts | 267 ++-------------------------------- yarn.lock | 14 +- 5 files changed, 26 insertions(+), 261 deletions(-) create mode 100644 changelogs/fragments/6915.yml diff --git a/changelogs/fragments/6915.yml b/changelogs/fragments/6915.yml new file mode 100644 index 000000000000..4944e5e6c32c --- /dev/null +++ b/changelogs/fragments/6915.yml @@ -0,0 +1,2 @@ +feat: +- Use JSON11 for handling long numerals ([#6915](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6915)) diff --git a/package.json b/package.json index 589426f08ab7..6e09cf84306d 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "**/jest-config": "npm:@amoo-miki/jest-config@27.5.1", "**/jest-jasmine2": "npm:@amoo-miki/jest-jasmine2@27.5.1", "**/joi/hoek": "npm:@amoo-miki/hoek@6.1.3", + "**/json11": "^1.1.2", "**/json-schema": "^0.4.0", "**/kind-of": ">=6.0.3", "**/loader-utils": "^2.0.4", @@ -154,7 +155,7 @@ "@hapi/vision": "^6.1.0", "@hapi/wreck": "^17.1.0", "@opensearch-project/opensearch": "^1.1.0", - "@opensearch-project/opensearch-next": "npm:@opensearch-project/opensearch@^2.6.0", + "@opensearch-project/opensearch-next": "npm:@opensearch-project/opensearch@^2.9.0", "@opensearch/datemath": "5.0.3", "@osd/ace": "1.0.0", "@osd/analytics": "1.0.0", diff --git a/packages/osd-std/package.json b/packages/osd-std/package.json index 3b1bea69bf8d..d0d859217c08 100644 --- a/packages/osd-std/package.json +++ b/packages/osd-std/package.json @@ -8,6 +8,7 @@ "private": true, "sideEffects": false, "dependencies": { + "json11": "^1.1.2", "lodash": "^4.17.21" }, "devDependencies": { diff --git a/packages/osd-std/src/json.ts b/packages/osd-std/src/json.ts index d8bb27e1eb6a..4dcd3eb03e65 100644 --- a/packages/osd-std/src/json.ts +++ b/packages/osd-std/src/json.ts @@ -3,260 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -/* In JavaScript, a `Number` is a 64-bit floating-point value which can store 16 digits. However, the - * serializer and deserializer will need to cater to numeric values generated by other languages which - * can have up to 19 digits. Native JSON parser and stringifier, incapable of handling the extra - * digits, corrupt the values, making them unusable. - * - * To work around this limitation, the deserializer converts long sequences of digits into strings and - * marks them before applying the parser. During the parsing, string values that begin with the mark - * are converted to `BigInt` values. - * Similarly, during stringification, the serializer converts `BigInt` values to marked strings and - * when done, it replaces them with plain numerals. - * - * `Number.MAX_SAFE_INTEGER`, 9,007,199,254,740,991, is the largest number that the native methods can - * parse and stringify, and any numeral greater than that would need to be translated using the - * workaround; all 17-digits or longer and only tail-end of the 16-digits need translation. It would - * be unfair to all the 16-digit numbers if the translation applied to `\d{16,}` only to cover the - * less than 10%. Hence, a RegExp is created to only match numerals too long to be a number. - * - * To make the explanation simpler, let's assume that MAX_SAFE_INTEGER is 8921 which has 4 digits. - * Starting from the right, we take each digit onwards, `[-9]`: - * 1) 7922 - 7929: 792[2-9]\d{0} - * 2) 7930 - 7999: 79[3-9]\d{1} - * 9) 9 + 1 = 10 which results in a rollover; no need to do anything. - * 8) 9000 - 9999: [9-9]\d{3} - * Finally we add anything 5 digits or longer: `\d{5,} - * - * Note: A better solution would use AST but considering its performance penalty, RegExp is the next - * best thing. - */ -const maxIntAsString = String(Number.MAX_SAFE_INTEGER); -const maxIntLength = maxIntAsString.length; -// Sub-patterns for each digit -const longNumeralMatcherTokens = [`\\d{${maxIntAsString.length + 1},}`]; -for (let i = 0; i < maxIntLength; i++) { - if (maxIntAsString[i] !== '9') { - longNumeralMatcherTokens.push( - maxIntAsString.substring(0, i) + - `[${parseInt(maxIntAsString[i], 10) + 1}-9]` + - `\\d{${maxIntLength - i - 1}}` - ); - } -} - -/* The matcher that looks for `": , ...}` and `[..., , ...]` - * - * The pattern starts by looking for `":` not immediately preceded by a `\`. That should be - * followed by any of the numeric sub-patterns. A comma, end of an array, end of an object, or - * the end of the input are the only acceptable elements after it. - * - * Note: This RegExp can result in false-positive hits on the likes of `{"key": "[ ]"}` and - * those are cleaned out during parsing. - */ -const longNumeralMatcher = new RegExp( - `((?:\\[|,|(? { - // coverage:ignore-line - if (!length || length < 0) return []; - const choices = []; - const arr = markerChars; - const arrLength = arr.length; - const temp = Array(length); - - (function fill(pos, start) { - if (pos === length) return choices.push(temp.join('')); - - for (let i = start; i < arrLength; i++) { - temp[pos] = arr[i]; - fill(pos + 1, i); - } - })(0, 0); - - return choices; -}; - -/* Experiments with different combinations of various lengths, until one is found to not be in - * the input string. - */ -const getMarker = (text: string): { marker: string; length: number } => { - let marker; - let length = 0; - do { - length++; - getMarkerChoices(length).some((markerChoice) => { - if (text.indexOf(markerChoice) === -1) { - marker = markerChoice; - return true; - } - }); - } while (!marker); - - return { - marker, - length, - }; -}; - -const parseStringWithLongNumerals = ( - text: string, - reviver?: ((this: any, key: string, value: any) => any) | null -): any => { - const { marker, length } = getMarker(text); - - let hadException; - let obj; - let markedJSON = text.replace(longNumeralMatcher, `$1"${marker}$2"$3`); - const markedValueMatcher = new RegExp(`^${marker}-?\\d+$`); - - /* Convert marked values to BigInt values. - * The `startsWith` is purely for performance, to avoid running `test` if not needed. - */ - const convertMarkedValues = (val: any) => - typeof val === 'string' && val.startsWith(marker) && markedValueMatcher.test(val) - ? BigInt(val.substring(length)) - : val; - - /* For better performance, instead of testing for existence of `reviver` on each value, two almost - * identical functions are used. - */ - const parseMarkedText = reviver - ? (markedText: string) => - JSON.parse(markedText, function (key, val) { - return reviver.call(this, key, convertMarkedValues(val)); - }) - : (markedText: string) => JSON.parse(markedText, (key, val) => convertMarkedValues(val)); - - /* RegExp cannot replace AST and the process of marking adds quotes. So, any false-positive hit - * will make the JSON string unparseable. - * - * To find those instances, we try to parse and watch for the location of any errors. If an error - * is caused by the marking, we remove that single marking and try again. - */ - try { - do { - try { - hadException = false; - obj = parseMarkedText(markedJSON); - } catch (e) { - hadException = true; - /* There are two types of exception objects that can be raised: - * 1) a textual message with the position that we need to parse - * i. Unexpected [token|string ...] at position ... - * ii. Expected ',' or ... after ... in JSON at position ... - * iii. expected ',' or ... after ... in object at line ... column ... - * 2) a proper object with lineNumber and columnNumber which we can use - * Note: this might refer to the part of the code that threw the exception but - * we will try it anyway; the regex is specific enough to not produce - * false-positives. - */ - let { lineNumber, columnNumber } = e; - - if (typeof e?.message === 'string') { - /* Check for 1-i and 1-ii - * Finding "..."෴1111"..." inside a string value, the extra quotes throw a syntax error - * and the position points to " that is assumed to be the begining of a value. - */ - let match = e.message.match(/^(?:Un)?expected .*at position (\d+)(\D|$)/i); - if (match) { - lineNumber = 1; - // Add 1 to reach the marker - columnNumber = parseInt(match[1], 10) + 1; - } else { - /* Check for 1-iii - * Finding "...,"෴1111"..." inside a string value, the extra quotes throw a syntax error - * and the column number points to the marker after the " that is assumed to be terminating the - * value. - * PS: There are different versions of this error across browsers and platforms. - */ - // ToDo: Add functional tests for this path - match = e.message.match(/expected .*line (\d+) column (\d+)(\D|$)/i); - if (match) { - lineNumber = parseInt(match[1], 10); - columnNumber = parseInt(match[2], 10); - } - } - } - - if (lineNumber < 1 || columnNumber < 2) { - /* The problem is not with this replacement. - * Note: This will never happen because the outer parse would have already thrown. - */ - // coverage:ignore-line - throw e; - } - - /* We need to skip e.lineNumber - 1 number of `\n` occurrences. - * Then, we need to go to e.columnNumber - 2 to look for `"\d+"`; we need to `-1` to - * account for the quote but an additional `-1` is needed because columnNumber starts from 1. - */ - const re = new RegExp( - `^((?:.*\\n){${lineNumber - 1}}[^\\n]{${columnNumber - 2}})"${marker}(-?\\d+)"` - ); - if (!re.test(markedJSON)) { - /* The exception is not caused by adding the marker. - * Note: This will never happen because the outer parse would have already thrown. - */ - // coverage:ignore-line - throw e; - } - - // We have found a bad replacement; let's remove it. - markedJSON = markedJSON.replace(re, '$1$2'); - } - } while (hadException); - } catch (ex) { - // If parsing of marked `text` fails, fallback to parsing the original `text` - obj = JSON.parse(text, reviver || undefined); - } - - return obj; -}; - -const stringifyObjectWithBigInts = ( - obj: any, - candidate: string, - replacer?: ((this: any, key: string, value: any) => any) | null, - space?: string | number -): string => { - const { marker } = getMarker(candidate); - - /* The matcher that looks for "" - * Because we have made sure that `marker` was never present in the original object, we can - * carelessly assume every "" is due to our marking. - */ - const markedBigIntMatcher = new RegExp(`"${marker}(-?\\d+)"`, 'g'); - - /* Convert BigInt values to a string and mark them. - * Can't be bothered with Number values outside the safe range because they are already corrupted. - * - * For better performance, instead of testing for existence of `replacer` on each value, two almost - * identical functions are used. - */ - const addMarkerToBigInts = replacer - ? function (this: any, key: string, val: any) { - // replacer is called before marking because marking changes the type - const newVal = replacer.call(this, key, val); - return typeof newVal === 'bigint' ? `${marker}${newVal.toString()}` : newVal; - } - : (key: string, val: any) => (typeof val === 'bigint' ? `${marker}${val.toString()}` : val); - - return ( - JSON.stringify(obj, addMarkerToBigInts, space) - // Replace marked substrings with just the numerals - .replace(markedBigIntMatcher, '$1') - ); -}; +import JSON11 from 'json11'; export const stringify = ( obj: any, @@ -298,7 +45,14 @@ export const stringify = ( text = JSON.stringify(obj, checkForBigInts, space); if (!numeralsAreNumbers) { - text = stringifyObjectWithBigInts(obj, text, replacer, space); + const temp = JSON11.stringify(obj, { + replacer, + space, + withBigInt: false, + quote: '"', + quoteNames: true, + }); + if (temp) text = temp; } return text; @@ -344,7 +98,8 @@ export const parse = ( obj = JSON.parse(text, checkForLargeNumerals); if (!numeralsAreNumbers) { - obj = parseStringWithLongNumerals(text, reviver); + const temp = JSON11.parse(text, reviver, { withLongNumerals: true }); + if (temp) obj = temp; } return obj; diff --git a/yarn.lock b/yarn.lock index d6084909cf0e..349ded92399b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2517,14 +2517,15 @@ mkdirp "^1.0.4" rimraf "^3.0.2" -"@opensearch-project/opensearch-next@npm:@opensearch-project/opensearch@^2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@opensearch-project/opensearch/-/opensearch-2.6.0.tgz#cbacb34f92aed04e98cabcdc0dc65eb495023880" - integrity sha512-zgDSa/qUpoEwA+Nxjtv0qtln63M+hS4SVO94R9XjwzJAoqsUiNMjjzF6D6Djq/xJMgCzIYjvBZ5vUlB8/kXwjQ== +"@opensearch-project/opensearch-next@npm:@opensearch-project/opensearch@^2.9.0": + version "2.9.0" + resolved "https://registry.yarnpkg.com/@opensearch-project/opensearch/-/opensearch-2.9.0.tgz#319b4d174540b6d000c31477a56618e5054c6fcb" + integrity sha512-BXPWSBME1rszZ8OvtBVQ9F6kLiZSENDSFPawbPa1fv0GouuQfWxkKSI9TcnfGLp869fgLTEIfeC5Qexd4RbAYw== dependencies: aws4 "^1.11.0" debug "^4.3.1" hpagent "^1.2.0" + json11 "^1.0.4" ms "^2.1.3" secure-json-parse "^2.4.0" @@ -11084,6 +11085,11 @@ json-stringify-safe@5.0.1, json-stringify-safe@^5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== +json11@^1.0.4, json11@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/json11/-/json11-1.1.2.tgz#35ffd3ee5073b0cc09ef826b0a0dc005ebef2b5b" + integrity sha512-5r1RHT1/Gr/jsI/XZZj/P6F11BKM8xvTaftRuiLkQI9Z2PFDukM82Ysxw8yDszb3NJP/NKnRlSGmhUdG99rlBw== + json5@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" From 9b6325c6c60fa7507b1ce70b1a7fe06b80110839 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 13:45:08 -0700 Subject: [PATCH 017/276] [VisBuilder] Change VisBuilder from experimental to production (#6436) (#6971) * [VisBuilder] Change VisBuilder from experimental to production Issue Resolve https://github.com/opensearch-project/OpenSearch-Dashboards/issues/6435 * Changeset file for PR #6436 created/updated --------- (cherry picked from commit 75e60874b68d2158cf6100c0b4e56d93d3997065) Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/6436.yml | 2 + .../components/experimental_info.tsx | 41 --------------- .../application/components/workspace.scss | 2 +- .../application/components/workspace.tsx | 8 +-- .../public/embeddable/disabled_embeddable.tsx | 34 ------------- .../embeddable/disabled_visualization.scss | 12 ----- .../embeddable/disabled_visualization.tsx | 31 ----------- .../vis_builder_embeddable_factory.tsx | 19 ++----- src/plugins/vis_builder/public/plugin.test.ts | 1 - src/plugins/vis_builder/public/plugin.ts | 2 - .../public/services/type_service/types.ts | 2 +- .../type_service/visualization_type.tsx | 2 +- .../apps/vis_builder/_experimental_vis.ts | 51 ------------------- test/functional/apps/vis_builder/index.ts | 1 - 14 files changed, 9 insertions(+), 199 deletions(-) create mode 100644 changelogs/fragments/6436.yml delete mode 100644 src/plugins/vis_builder/public/application/components/experimental_info.tsx delete mode 100644 src/plugins/vis_builder/public/embeddable/disabled_embeddable.tsx delete mode 100644 src/plugins/vis_builder/public/embeddable/disabled_visualization.scss delete mode 100644 src/plugins/vis_builder/public/embeddable/disabled_visualization.tsx delete mode 100644 test/functional/apps/vis_builder/_experimental_vis.ts diff --git a/changelogs/fragments/6436.yml b/changelogs/fragments/6436.yml new file mode 100644 index 000000000000..5877e0562d6f --- /dev/null +++ b/changelogs/fragments/6436.yml @@ -0,0 +1,2 @@ +feat: +- [VisBuilder] Change VisBuilder from experimental to production ([#6436](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6436)) \ No newline at end of file diff --git a/src/plugins/vis_builder/public/application/components/experimental_info.tsx b/src/plugins/vis_builder/public/application/components/experimental_info.tsx deleted file mode 100644 index ea341e1e8873..000000000000 --- a/src/plugins/vis_builder/public/application/components/experimental_info.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { memo } from 'react'; -import { EuiCallOut, EuiLink } from '@elastic/eui'; -import { FormattedMessage } from '@osd/i18n/react'; -import { i18n } from '@osd/i18n'; - -export const InfoComponent = () => { - return ( - - - the GitHub issue - - ), - }} - /> - - ); -}; - -export const ExperimentalInfo = memo(InfoComponent); diff --git a/src/plugins/vis_builder/public/application/components/workspace.scss b/src/plugins/vis_builder/public/application/components/workspace.scss index 09285ab14985..70bb078b927e 100644 --- a/src/plugins/vis_builder/public/application/components/workspace.scss +++ b/src/plugins/vis_builder/public/application/components/workspace.scss @@ -11,7 +11,7 @@ $keyframe-multiplier: calc(1 / $animation-multiplier); .vbWorkspace { display: grid; -ms-grid-rows: auto $euiSizeM 1fr; - grid-template-rows: auto 1fr; + grid-template-rows: 1fr; grid-area: workspace; grid-gap: $euiSizeM; padding: $euiSizeM; diff --git a/src/plugins/vis_builder/public/application/components/workspace.tsx b/src/plugins/vis_builder/public/application/components/workspace.tsx index 31880e93bb7f..295ed5284342 100644 --- a/src/plugins/vis_builder/public/application/components/workspace.tsx +++ b/src/plugins/vis_builder/public/application/components/workspace.tsx @@ -4,7 +4,7 @@ */ import { i18n } from '@osd/i18n'; -import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiPanel } from '@elastic/eui'; +import { EuiEmptyPrompt, EuiFlexItem, EuiIcon, EuiPanel } from '@elastic/eui'; import React, { useState, useMemo, useEffect, useLayoutEffect } from 'react'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { IExpressionLoaderParams } from '../../../../expressions/public'; @@ -18,7 +18,6 @@ import hand_field from '../../assets/hand_field.svg'; import fields_bg from '../../assets/fields_bg.svg'; import './workspace.scss'; -import { ExperimentalInfo } from './experimental_info'; import { handleVisEvent } from '../utils/handle_vis_event'; export const WorkspaceUI = () => { @@ -105,11 +104,6 @@ export const WorkspaceUI = () => { return (
- - - - - {expression ? ( { - private domNode?: HTMLElement; - public readonly type = VISBUILDER_EMBEDDABLE; - - constructor(private readonly title: string, initialInput: VisBuilderInput) { - super(initialInput, { title }); - } - - public reload() {} - public render(domNode: HTMLElement) { - if (this.title) { - this.domNode = domNode; - ReactDOM.render(, domNode); - } - } - - public destroy() { - if (this.domNode) { - ReactDOM.unmountComponentAtNode(this.domNode); - } - } -} diff --git a/src/plugins/vis_builder/public/embeddable/disabled_visualization.scss b/src/plugins/vis_builder/public/embeddable/disabled_visualization.scss deleted file mode 100644 index 825ff4d73223..000000000000 --- a/src/plugins/vis_builder/public/embeddable/disabled_visualization.scss +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ -.vbDisabledVisualization { - width: 100%; - display: grid; - grid-gap: $euiSize; - place-content: center; - place-items: center; - text-align: center; -} diff --git a/src/plugins/vis_builder/public/embeddable/disabled_visualization.tsx b/src/plugins/vis_builder/public/embeddable/disabled_visualization.tsx deleted file mode 100644 index 30b5dd5ffa3f..000000000000 --- a/src/plugins/vis_builder/public/embeddable/disabled_visualization.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiIcon } from '@elastic/eui'; -import { FormattedMessage } from '@osd/i18n/react'; -import React from 'react'; - -import './disabled_visualization.scss'; - -export function DisabledVisualization({ title }: { title: string }) { - return ( -
- -
- {title} }} - /> -
-
- -
-
- ); -} diff --git a/src/plugins/vis_builder/public/embeddable/vis_builder_embeddable_factory.tsx b/src/plugins/vis_builder/public/embeddable/vis_builder_embeddable_factory.tsx index 3c0bf0337369..52cc74c82e0c 100644 --- a/src/plugins/vis_builder/public/embeddable/vis_builder_embeddable_factory.tsx +++ b/src/plugins/vis_builder/public/embeddable/vis_builder_embeddable_factory.tsx @@ -11,7 +11,6 @@ import { IContainer, SavedObjectEmbeddableInput, } from '../../../embeddable/public'; -import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../visualizations/public'; import { EDIT_PATH, PLUGIN_ID, @@ -19,7 +18,6 @@ import { VisBuilderSavedObjectAttributes, VISBUILDER_SAVED_OBJECT, } from '../../common'; -import { DisabledEmbeddable } from './disabled_embeddable'; import { VisBuilderEmbeddable, VisBuilderInput, @@ -27,12 +25,7 @@ import { VISBUILDER_EMBEDDABLE, } from './vis_builder_embeddable'; import { getStateFromSavedObject } from '../saved_visualizations/transforms'; -import { - getHttp, - getSavedVisBuilderLoader, - getTimeFilter, - getUISettings, -} from '../plugin_services'; +import { getHttp, getSavedVisBuilderLoader, getTimeFilter } from '../plugin_services'; import { StartServicesGetter } from '../../../opensearch_dashboards_utils/public'; import { VisBuilderPluginStartDependencies } from '../types'; @@ -45,7 +38,7 @@ export class VisBuilderEmbeddableFactory EmbeddableFactoryDefinition< SavedObjectEmbeddableInput, VisBuilderOutput | EmbeddableOutput, - VisBuilderEmbeddable | DisabledEmbeddable, + VisBuilderEmbeddable, VisBuilderSavedObjectAttributes > { public readonly type = VISBUILDER_EMBEDDABLE; @@ -75,17 +68,11 @@ export class VisBuilderEmbeddableFactory savedObjectId: string, input: VisBuilderInput, parent?: IContainer - ): Promise { + ): Promise { try { const savedObject = await getSavedVisBuilderLoader().get(savedObjectId); const editPath = `${EDIT_PATH}/${savedObjectId}`; const editUrl = getHttp().basePath.prepend(`/app/${PLUGIN_ID}${editPath}`); - const isLabsEnabled = getUISettings().get(VISUALIZE_ENABLE_LABS_SETTING); - - if (!isLabsEnabled) { - return new DisabledEmbeddable(PLUGIN_NAME, input); - } - const savedVis = getStateFromSavedObject(savedObject); const indexPatternService = this.deps.start().plugins.data.indexPatterns; const indexPattern = await indexPatternService.get( diff --git a/src/plugins/vis_builder/public/plugin.test.ts b/src/plugins/vis_builder/public/plugin.test.ts index 35e17865649a..f6f3a8a6e830 100644 --- a/src/plugins/vis_builder/public/plugin.test.ts +++ b/src/plugins/vis_builder/public/plugin.test.ts @@ -39,7 +39,6 @@ describe('VisBuilderPlugin', () => { title: PLUGIN_NAME, aliasPath: '#/', aliasApp: PLUGIN_ID, - stage: 'experimental', }) ); }); diff --git a/src/plugins/vis_builder/public/plugin.ts b/src/plugins/vis_builder/public/plugin.ts index fefd3107be66..b0378bffd073 100644 --- a/src/plugins/vis_builder/public/plugin.ts +++ b/src/plugins/vis_builder/public/plugin.ts @@ -192,7 +192,6 @@ export class VisBuilderPlugin defaultMessage: 'Create visualizations using the new VisBuilder', }), icon: 'visBuilder', - stage: 'experimental', aliasApp: PLUGIN_ID, aliasPath: '#/', appExtensions: { @@ -205,7 +204,6 @@ export class VisBuilderPlugin icon: 'visBuilder', id, savedObjectType: VISBUILDER_SAVED_OBJECT, - stage: 'experimental', title: attributes?.title, typeTitle: VIS_BUILDER_CHART_TYPE, updated_at: updatedAt, diff --git a/src/plugins/vis_builder/public/services/type_service/types.ts b/src/plugins/vis_builder/public/services/type_service/types.ts index edcc0b659fc7..bc0a5cfe6c61 100644 --- a/src/plugins/vis_builder/public/services/type_service/types.ts +++ b/src/plugins/vis_builder/public/services/type_service/types.ts @@ -22,7 +22,7 @@ export interface VisualizationTypeOptions { readonly title: string; readonly description?: string; readonly icon: IconType; - readonly stage?: 'experimental' | 'production'; + readonly stage?: 'production'; readonly ui: { containerConfig: { data: DataTabConfig; diff --git a/src/plugins/vis_builder/public/services/type_service/visualization_type.tsx b/src/plugins/vis_builder/public/services/type_service/visualization_type.tsx index 2f863316435e..0c2fadf3cf38 100644 --- a/src/plugins/vis_builder/public/services/type_service/visualization_type.tsx +++ b/src/plugins/vis_builder/public/services/type_service/visualization_type.tsx @@ -14,7 +14,7 @@ export class VisualizationType implements IVisualizationType { public readonly title: string; public readonly description: string; public readonly icon: IconType; - public readonly stage: 'experimental' | 'production'; + public readonly stage: 'production'; public readonly ui: IVisualizationType['ui']; public readonly toExpression: ( state: RenderState, diff --git a/test/functional/apps/vis_builder/_experimental_vis.ts b/test/functional/apps/vis_builder/_experimental_vis.ts deleted file mode 100644 index 1743d4882281..000000000000 --- a/test/functional/apps/vis_builder/_experimental_vis.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import expect from '@osd/expect'; -import { VISUALIZE_ENABLE_LABS_SETTING } from '../../../../src/plugins/visualizations/common/constants'; -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['visualize', 'visBuilder']); - const log = getService('log'); - const opensearchDashboardsServer = getService('opensearchDashboardsServer'); - - describe('experimental settings for visBuilder app ', function () { - it('should show an notification when creating visBuilder visualization', async () => { - log.debug('navigateToApp visualize'); - await PageObjects.visualize.navigateToNewVisualization(); - await PageObjects.visualize.waitForVisualizationSelectPage(); - - // Try to find the visBuilder Vis type. - const visBuilderVisTypeExists = await PageObjects.visualize.hasVisType('vis-builder'); - expect(visBuilderVisTypeExists).to.be(true); - - // Create a new visualization - await PageObjects.visualize.clickVisType('vis-builder'); - - // Check that the experimental banner is there and state that this is experimental - const info = await PageObjects.visBuilder.getExperimentalInfo(); - expect(await info.getVisibleText()).to.contain('experimental'); - }); - - it('should not be available in the picker when disabled', async () => { - log.debug('navigateToApp visualize'); - await opensearchDashboardsServer.uiSettings.replace({ - [VISUALIZE_ENABLE_LABS_SETTING]: false, - }); - await PageObjects.visualize.navigateToNewVisualization(); - await PageObjects.visualize.waitForVisualizationSelectPage(); - - // Try to find the visBuilder Vis type. - const visBuilderVisTypeExists = await PageObjects.visualize.hasVisType('vis-builder'); - expect(visBuilderVisTypeExists).to.be(false); - }); - - after(async () => { - // unset the experimental ui setting - await opensearchDashboardsServer.uiSettings.unset(VISUALIZE_ENABLE_LABS_SETTING); - }); - }); -} diff --git a/test/functional/apps/vis_builder/index.ts b/test/functional/apps/vis_builder/index.ts index c0e7b9c35c77..67b333deb5d6 100644 --- a/test/functional/apps/vis_builder/index.ts +++ b/test/functional/apps/vis_builder/index.ts @@ -34,6 +34,5 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); loadTestFile(require.resolve('./_base')); - loadTestFile(require.resolve('./_experimental_vis')); }); } From f8d49d54d6c855a8d5d1b5cf214509493b84692c Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 7 Jun 2024 15:19:57 -0700 Subject: [PATCH 018/276] Modify the import for timeline visualization to includes data source name in MDS scenario (#6954) (#6975) (cherry picked from commit 7eaab64fdff8b1f9b0f4bbca0ede09ca523159c9) Signed-off-by: Yuanqi(Ella) Zhu Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../check_conflict_for_data_source.test.ts | 114 ++++++++++++++++++ .../import/check_conflict_for_data_source.ts | 18 +++ .../import/create_saved_objects.test.ts | 114 +++++++++++++++++- .../import/create_saved_objects.ts | 18 +++ .../import/import_saved_objects.ts | 3 +- 5 files changed, 263 insertions(+), 4 deletions(-) diff --git a/src/core/server/saved_objects/import/check_conflict_for_data_source.test.ts b/src/core/server/saved_objects/import/check_conflict_for_data_source.test.ts index 2b09a1c853c4..f6628df1a727 100644 --- a/src/core/server/saved_objects/import/check_conflict_for_data_source.test.ts +++ b/src/core/server/saved_objects/import/check_conflict_for_data_source.test.ts @@ -318,6 +318,120 @@ describe('#checkConflictsForDataSource', () => { ); }); + /* + * Timeline test cases + */ + it('will not change timeline expression when importing from datasource to different datasource', async () => { + const timelineSavedObject = createObject('visualization', 'old-datasource-id_some-object-id'); + // @ts-expect-error + timelineSavedObject.attributes.visState = + '{"title":"(Timeline) Avg bytes over time","type":"timelion","aggs":[],"params":{"expression":".opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name=newDataSource).lines(show=true).points(show=true).yaxis(label=\\"Average bytes\\")","interval":"auto"}}'; + const params = setupParams({ + objects: [timelineSavedObject], + ignoreRegularConflicts: true, + dataSourceId: 'some-datasource-id', + savedObjectsClient: getSavedObjectClient(), + }); + const checkConflictsForDataSourceResult = await checkConflictsForDataSource(params); + + expect(checkConflictsForDataSourceResult).toEqual( + expect.objectContaining({ + filteredObjects: [ + { + ...timelineSavedObject, + attributes: { + title: 'some-title', + visState: + '{"title":"(Timeline) Avg bytes over time","type":"timelion","aggs":[],"params":{"expression":".opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name=newDataSource).lines(show=true).points(show=true).yaxis(label=\\"Average bytes\\")","interval":"auto"}}', + }, + id: 'some-datasource-id_some-object-id', + }, + ], + errors: [], + importIdMap: new Map([ + [ + `visualization:old-datasource-id_some-object-id`, + { id: 'some-datasource-id_some-object-id', omitOriginId: true }, + ], + ]), + }) + ); + }); + + it('will change timeline expression when importing expression does not have a datasource name', async () => { + const timelineSavedObject = createObject('visualization', 'old-datasource-id_some-object-id'); + // @ts-expect-error + timelineSavedObject.attributes.visState = + '{"title":"(Timeline) Avg bytes over time","type":"timelion","aggs":[],"params":{"expression":".opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp).lines(show=true).points(show=true).yaxis(label=\\"Average bytes\\")","interval":"auto"}}'; + const params = setupParams({ + objects: [timelineSavedObject], + ignoreRegularConflicts: true, + dataSourceId: 'some-datasource-id', + savedObjectsClient: getSavedObjectClient(), + }); + const checkConflictsForDataSourceResult = await checkConflictsForDataSource(params); + + expect(checkConflictsForDataSourceResult).toEqual( + expect.objectContaining({ + filteredObjects: [ + { + ...timelineSavedObject, + attributes: { + title: 'some-title', + visState: + '{"title":"(Timeline) Avg bytes over time","type":"timelion","aggs":[],"params":{"expression":".opensearch(opensearch_dashboards_sample_data_logs, metric=avg:bytes, timefield=@timestamp, data_source_name=\\"some-datasource-title\\").lines(show=true).points(show=true).yaxis(label=\\"Average bytes\\")","interval":"auto"}}', + }, + id: 'some-datasource-id_some-object-id', + }, + ], + errors: [], + importIdMap: new Map([ + [ + `visualization:old-datasource-id_some-object-id`, + { id: 'some-datasource-id_some-object-id', omitOriginId: true }, + ], + ]), + }) + ); + }); + + it('When there are multiple opensearch queries in the expression, it would go through each query and add data source name if it does not have any.', async () => { + const timelineSavedObject = createObject('visualization', 'old-datasource-id_some-object-id'); + // @ts-expect-error + timelineSavedObject.attributes.visState = + '{"title":"some-other-title","type":"timelion","params":{"expression":".es(index=old-datasource-title, timefield=@timestamp, data_source_name=\\"aos 211\\"), .elasticsearch(index=old-datasource-title, timefield=@timestamp)"},"aggs":[]}'; + const params = setupParams({ + objects: [timelineSavedObject], + ignoreRegularConflicts: true, + dataSourceId: 'some-datasource-id', + savedObjectsClient: getSavedObjectClient(), + }); + const checkConflictsForDataSourceResult = await checkConflictsForDataSource(params); + + expect(checkConflictsForDataSourceResult).toEqual( + expect.objectContaining({ + filteredObjects: [ + { + ...timelineSavedObject, + attributes: { + title: 'some-title', + visState: + '{"title":"some-other-title","type":"timelion","params":{"expression":".es(index=old-datasource-title, timefield=@timestamp, data_source_name=\\"aos 211\\"), .elasticsearch(index=old-datasource-title, timefield=@timestamp, data_source_name=\\"some-datasource-title\\")"},"aggs":[]}', + }, + id: 'some-datasource-id_some-object-id', + }, + ], + errors: [], + importIdMap: new Map([ + [ + `visualization:old-datasource-id_some-object-id`, + { id: 'some-datasource-id_some-object-id', omitOriginId: true }, + ], + ]), + }) + ); + }); + /** * TSVB test cases */ diff --git a/src/core/server/saved_objects/import/check_conflict_for_data_source.ts b/src/core/server/saved_objects/import/check_conflict_for_data_source.ts index f04dd0c6f69e..0b7f64137faf 100644 --- a/src/core/server/saved_objects/import/check_conflict_for_data_source.ts +++ b/src/core/server/saved_objects/import/check_conflict_for_data_source.ts @@ -15,6 +15,8 @@ import { getDataSourceTitleFromId, getUpdatedTSVBVisState, updateDataSourceNameInVegaSpec, + extractTimelineExpression, + updateDataSourceNameInTimeline, } from './utils'; export interface ConflictsForDataSourceParams { @@ -120,6 +122,22 @@ export async function checkConflictsForDataSource({ } } + // For timeline visualizations, update the data source name in the timeline expression + const timelineExpression = extractTimelineExpression(object); + if (!!timelineExpression && !!dataSourceTitle) { + // Get the timeline expression with the updated data source name + const modifiedExpression = updateDataSourceNameInTimeline( + timelineExpression, + dataSourceTitle + ); + + // @ts-expect-error + const timelineStateObject = JSON.parse(object.attributes?.visState); + timelineStateObject.params.expression = modifiedExpression; + // @ts-expect-error + object.attributes.visState = JSON.stringify(timelineStateObject); + } + if (!!dataSourceId) { const visualizationObject = object as VisualizationObject; const { visState, references } = getUpdatedTSVBVisState( diff --git a/src/core/server/saved_objects/import/create_saved_objects.test.ts b/src/core/server/saved_objects/import/create_saved_objects.test.ts index da7f057435ad..2237017f3400 100644 --- a/src/core/server/saved_objects/import/create_saved_objects.test.ts +++ b/src/core/server/saved_objects/import/create_saved_objects.test.ts @@ -169,6 +169,39 @@ const getVegaMDSVisualizationObj = (id: string, dataSourceId: string) => ({ }, ], }); + +const getTimelineVisualizationObj = (id: string, dataSourceId: string) => ({ + type: 'visualization', + id: dataSourceId ? `${dataSourceId}_${id}` : id, + attributes: { + title: 'some-other-title', + visState: + '{"title":"some-other-title","type":"timelion","params":{"expression":".es(index=old-datasource-title, timefield=@timestamp)"},"aggs":[]}', + }, + references: [], +}); + +const getTimelineVisualizationObjWithMultipleQueries = (id: string, dataSourceId: string) => ({ + type: 'visualization', + id: dataSourceId ? `${dataSourceId}_${id}` : id, + attributes: { + title: 'some-other-title', + visState: + '{"title":"some-other-title","type":"timelion","params":{"expression":".es(index=old-datasource-title, timefield=@timestamp, data_source_name=\\"aos 211\\"), .elasticsearch(index=old-datasource-title, timefield=@timestamp)"},"aggs":[]}', + }, + references: [], +}); + +const getTimelineVisualizationObjWithDataSourceName = (id: string, dataSourceId: string) => ({ + type: 'visualization', + id: dataSourceId ? `${dataSourceId}_${id}` : id, + attributes: { + title: 'some-other-title', + visState: + '{"title":"some-other-title","type":"timelion","params":{"expression":".es(index=old-datasource-title, timefield=@timestamp, data_source_name=ds1)"},"aggs":[]}', + }, + references: [], +}); // non-multi-namespace types shouldn't have origin IDs, but we include test cases to ensure it's handled gracefully // non-multi-namespace types by definition cannot result in an unresolvable conflict, so we don't include test cases for those const importId3 = 'id-foo'; @@ -571,7 +604,7 @@ describe('#createSavedObjects', () => { expect(results).toEqual(expectedResultsWithDataSource); }; - const testVegaVisualizationsWithDataSources = async (params: { + const testVegaTimelineVisualizationsWithDataSources = async (params: { objects: SavedObject[]; expectedFilteredObjects: Array>; dataSourceId?: string; @@ -673,7 +706,7 @@ describe('#createSavedObjects', () => { ], }, ]; - await testVegaVisualizationsWithDataSources({ + await testVegaTimelineVisualizationsWithDataSources({ objects, expectedFilteredObjects, dataSourceId: 'some-datasource-id', @@ -699,7 +732,82 @@ describe('#createSavedObjects', () => { }, }, ]; - await testVegaVisualizationsWithDataSources({ + await testVegaTimelineVisualizationsWithDataSources({ + objects, + expectedFilteredObjects, + dataSourceId: 'some-datasource-id', + dataSourceTitle: 'dataSourceName', + }); + }); + }); + + describe('with a data source for timeline saved objects', () => { + test('can attach a data source name to the timeline expression', async () => { + const objects = [getTimelineVisualizationObj('some-timeline-id', 'some-datasource-id')]; + const expectedObject = getTimelineVisualizationObj('some-timeline-id', 'some-datasource-id'); + const expectedFilteredObjects = [ + { + ...expectedObject, + attributes: { + title: 'some-other-title_dataSourceName', + visState: + '{"title":"some-other-title","type":"timelion","params":{"expression":".es(index=old-datasource-title, timefield=@timestamp, data_source_name=\\"dataSourceName\\")"},"aggs":[]}', + }, + }, + ]; + await testVegaTimelineVisualizationsWithDataSources({ + objects, + expectedFilteredObjects, + dataSourceId: 'some-datasource-id', + dataSourceTitle: 'dataSourceName', + }); + }); + + test('will not update the data source name in the timeline expression if no local cluster queries', async () => { + const objects = [ + getTimelineVisualizationObjWithDataSourceName('some-timeline-id', 'old-datasource-id'), + ]; + const expectedObject = getTimelineVisualizationObjWithDataSourceName( + 'some-timeline-id', + 'old-datasource-id' + ); + const expectedFilteredObjects = [ + { + ...expectedObject, + attributes: { + title: 'some-other-title_dataSourceName', + visState: + '{"title":"some-other-title","type":"timelion","params":{"expression":".es(index=old-datasource-title, timefield=@timestamp, data_source_name=ds1)"},"aggs":[]}', + }, + }, + ]; + await testVegaTimelineVisualizationsWithDataSources({ + objects, + expectedFilteredObjects, + dataSourceId: 'some-datasource-id', + dataSourceTitle: 'dataSourceName', + }); + }); + + test('When muliple opensearch query exists in expression, we can add data source name to the queries that missing data source name.', async () => { + const objects = [ + getTimelineVisualizationObjWithMultipleQueries('some-timeline-id', 'some-datasource-id'), + ]; + const expectedObject = getTimelineVisualizationObjWithMultipleQueries( + 'some-timeline-id', + 'some-datasource-id' + ); + const expectedFilteredObjects = [ + { + ...expectedObject, + attributes: { + title: 'some-other-title_dataSourceName', + visState: + '{"title":"some-other-title","type":"timelion","params":{"expression":".es(index=old-datasource-title, timefield=@timestamp, data_source_name=\\"aos 211\\"), .elasticsearch(index=old-datasource-title, timefield=@timestamp, data_source_name=\\"dataSourceName\\")"},"aggs":[]}', + }, + }, + ]; + await testVegaTimelineVisualizationsWithDataSources({ objects, expectedFilteredObjects, dataSourceId: 'some-datasource-id', diff --git a/src/core/server/saved_objects/import/create_saved_objects.ts b/src/core/server/saved_objects/import/create_saved_objects.ts index 7e3854107a29..a90ad802edaa 100644 --- a/src/core/server/saved_objects/import/create_saved_objects.ts +++ b/src/core/server/saved_objects/import/create_saved_objects.ts @@ -40,6 +40,8 @@ import { extractVegaSpecFromSavedObject, getUpdatedTSVBVisState, updateDataSourceNameInVegaSpec, + extractTimelineExpression, + updateDataSourceNameInTimeline, } from './utils'; interface CreateSavedObjectsParams { @@ -130,6 +132,22 @@ export const createSavedObjects = async ({ }); } + // Some visualization types will need special modifications, like TSVB visualizations + const timelineExpression = extractTimelineExpression(object); + if (!!timelineExpression && !!dataSourceTitle) { + // Get the timeline expression with the updated data source name + const modifiedExpression = updateDataSourceNameInTimeline( + timelineExpression, + dataSourceTitle + ); + + // @ts-expect-error + const timelineStateObject = JSON.parse(object.attributes?.visState); + timelineStateObject.params.expression = modifiedExpression; + // @ts-expect-error + object.attributes.visState = JSON.stringify(timelineStateObject); + } + const visualizationObject = object as VisualizationObject; const { visState, references } = getUpdatedTSVBVisState( visualizationObject, diff --git a/src/core/server/saved_objects/import/import_saved_objects.ts b/src/core/server/saved_objects/import/import_saved_objects.ts index cfd091149004..1289af145c58 100644 --- a/src/core/server/saved_objects/import/import_saved_objects.ts +++ b/src/core/server/saved_objects/import/import_saved_objects.ts @@ -72,7 +72,8 @@ export async function importSavedObjectsFromStream({ supportedTypes, dataSourceId, }); - // if not enable data_source, throw error early + // if dataSource is not enabled, but object type is data-source, or saved object id contains datasource id + // return unsupported type error if (!dataSourceEnabled) { const notSupportedErrors: SavedObjectsImportError[] = collectSavedObjectsResult.collectedObjects.reduce( (errors: SavedObjectsImportError[], obj) => { From 87d9ee080699c4dcdd3783c6276a3e5762f45629 Mon Sep 17 00:00:00 2001 From: Huan Jiang Date: Mon, 10 Jun 2024 09:31:48 -0700 Subject: [PATCH 019/276] Revert #6681 on 2.x since need more test coverage (#6978) Signed-off-by: Huan Jiang --- CHANGELOG.md | 1 - docs/theme.md | 131 -------- src/core/public/osd_bootstrap.test.ts | 1 - src/core/public/osd_bootstrap.ts | 5 - .../public/ui_settings/ui_settings_client.ts | 43 +-- .../rendering_service.test.ts.snap | 7 + .../server/rendering/rendering_service.tsx | 74 ++++- src/core/server/rendering/types.ts | 3 +- .../__snapshots__/template.test.tsx.snap | 305 ++++-------------- src/core/server/rendering/views/fonts.tsx | 32 +- src/core/server/rendering/views/styles.tsx | 28 +- .../server/rendering/views/template.test.tsx | 1 - src/core/server/rendering/views/template.tsx | 65 +--- src/core/server/rendering/views/theme.ts | 41 +++ src/core/server/ui_settings/settings/theme.ts | 16 - src/core/types/ui_settings.ts | 2 - .../ui/ui_render/bootstrap/app_bootstrap.js | 9 +- .../{bootstrap.js.hbs => template.js.hbs} | 35 +- src/legacy/ui/ui_render/ui_render_mixin.js | 142 +++----- .../public/header_user_theme_menu.tsx | 192 ----------- .../management_app/advanced_settings.tsx | 2 - .../management_app/components/field/field.tsx | 20 +- .../management_app/lib/to_editable_config.ts | 3 - .../public/management_app/types.ts | 1 - .../advanced_settings/public/plugin.ts | 10 +- .../public/register_nav_control.tsx | 29 -- .../server/collectors/management/schema.ts | 1 - src/plugins/telemetry/schema/oss_plugins.json | 3 - .../apps/visualize/_custom_branding.ts | 6 +- .../screenshots/baseline/tsvb_dashboard.png | Bin 49473 -> 48369 bytes 30 files changed, 308 insertions(+), 900 deletions(-) delete mode 100644 docs/theme.md create mode 100644 src/core/server/rendering/views/theme.ts rename src/legacy/ui/ui_render/bootstrap/{bootstrap.js.hbs => template.js.hbs} (67%) delete mode 100644 src/plugins/advanced_settings/public/header_user_theme_menu.tsx delete mode 100644 src/plugins/advanced_settings/public/register_nav_control.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f7d089ba687..33f8dab98a9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,7 +66,6 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Multiple Datasource] Able to Hide "Local Cluster" option from datasource DropDown ([#5827](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5827)) - [Multiple Datasource] Add api registry and allow it to be added into client config in data source plugin ([#5895](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5895)) - [Multiple Datasource] Refactor client and legacy client to use authentication registry ([#5881](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5881)) -- [Theme] Make theme and dark mode settings user/device specific (in local storage), with opt-out ([#5652](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5652)) ### 🐛 Bug Fixes diff --git a/docs/theme.md b/docs/theme.md deleted file mode 100644 index 293c65661c04..000000000000 --- a/docs/theme.md +++ /dev/null @@ -1,131 +0,0 @@ -# Theme System - -## Basic concepts - -### Theme definitions in OUI - -Themes are defined in OUI via https://github.com/opensearch-project/oui/blob/main/src/themes/themes.ts. When Building OUI, there are several theming artifacts generated (beyond the react components) for each mode (light/dark) of each theme: - -1. Theme compiled stylesheets (e.g. `@elastic/eui/dist/eui_theme_dark.css`). Consumed as entry files in [/packages/osd-ui-shared-deps/webpack.config.js](/packages/osd-ui-shared-deps/webpack.config.js) and republished by `osd-ui-shared-deps` (e.g. [UiSharedDeps.darkCssDistFilename](/packages/osd-ui-shared-deps/index.js)). -2. Theme compiled and minified stylesheets (e.g. `@elastic/eui/dist/eui_theme_dark.min.css`). These appear unused by OpenSearch Dashboards -3. Theme computed SASS variables as JSON (e.g. `@elastic/eui/dist/eui_theme_dark.json`). Consumed by [/packages/osd-ui-shared-deps/theme.ts](/packages/osd-ui-shared-deps/theme.ts) and made available to other components via the mode and theme aware `euiThemeVars`. In general, these should not be consumed by any other component directly. -4. Theme type definition file for SASS variables as JSON (e.g. `@elastic/eui/dist/eui_theme_dark.json.d.ts`) - -Note that all of these artifacts should ideally only be imported or used directly in one place (by `osd-ui-shared-deps`). - -In addition to these artifacts, OpenSearch Dashboards also makes heavy use of the theme SASS variables and mixins as defined in the source files (e.g. `@elastic/eui/src/theme_dark.scss`). - -### Theme definitions in OpenSearch Dashboards - -1. Theme tags are defined in [/packages/osd-optimizer/src/common/theme_tags.ts](/packages/osd-optimizer/src/common/theme_tags.ts) corresponding to each mode (light/dark) of each OUI theme. -2. These tags must correspond to entrypoint SCSS files in [/src/core/public/core_app/styles/](/src/core/public/core_app/styles/_globals_v8dark.scss), because they are imported by all SCSS files as part of the `sass-loader` in [/packages/osd-optimizer/src/worker/webpack.config.ts](/packages/osd-optimizer/src/worker/webpack.config.ts) and [/packages/osd-optimizer/src/worker/theme_loader.ts](/packages/osd-optimizer/src/worker/theme_loader.ts). Note that the optimizer webpack will compile a separate stylesheet for each unique mode and theme combination. -3. OUI SCSS source files are also imported by `osd-ui-framework`, which generates the legacy KUI stylesheets (e.g. [/packages/osd-ui-framework/src/kui_next_dark.scss](/packages/osd-ui-framework/src/kui_next_dark.scss)). KUI is a UI library that predates EUI/OUI, and should be deprecated and fully removed via [#1060](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/1060). Because it's a legacy package it has its own build process that doesn't use webpack; it just [compiles the SCSS files with grunt](/packages/osd-ui-framework/Gruntfile.js). But similarly to 2., a separate stylesheet is generated for each mode and theme combination. - -### Thmemed assets in OpenSearch Dasboards - -In general, most themed assests can be found in [/src/core/server/core_app/assets](src/core/server/core_app/assets/fonts/readme.md) (it also includes non-themed assets such as `favicons`, which could easily be themed if desired in the future). - -Most of the graphics/images are only dark/light mode-specific, not theme-specific: - -1. `default_branding` marks -2. `logos` - -This directory also includes legacy CSS files ([/src/core/server/core_app/assets/legacy_dark_theme.css](/src/core/server/core_app/assets/legacy_dark_theme.css) and [/src/core/server/core_app/assets/legacy_light_theme.css](/src/core/server/core_app/assets/legacy_light_theme.css)), which predate even KUI, and are still used by some plugins (notably `discover`). See [#4385](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4385) for an experiment in removing these. Unlike KUI, they don't rely on OUI themes at all. - -Finally, font assets are a bit of a special case. Theme-specific fonts are defined by OUI, but it doesn't include the font definitions directly. Instead, the font assets are in [/src/core/server/core_app/assets/fonts](/src/core/server/core_app/assets/fonts/readme.md). The corresponding `@font-face` style definitions are generated at runtime via [/src/core/server/rendering/views/fonts.tsx](/src/core/server/rendering/views/fonts.tsx). - -## Theme settings - -## Theme loading - -```mermaid -sequenceDiagram - autonumber - critical Setup - core/server->>core/server/rendering: setup rendering service - core/server/rendering->>core/server: provide render() method - core/server->>core/server: setup legacy service - core/server->>legacy: create legacy server - legacy->>legacy: start ui mixin to
handle special routes - core/server->>core/server/core_app: setup core app - core/server/core_app->>core/server/core_app: register default routes - core/server/core_app->>core/server/core_app: register static asset dir routes - end - Browser->>core/server: OSD page request (e.g. /app/home#/ ) - core/server->>core/server/core_app: request to default route
(via `http` service) - core/server/core_app->>core/server: call renderCoreApp() - core/server->>core/server/rendering: call render() - critical Initial page bootstrap - core/server/rendering->>core/server/rendering: get theme settings from config - core/server/rendering->>core/server/rendering: assign branding values \
(including dark mode) - core/server/rendering->>Browser: return static loading page template - Note over core/server/rendering,Browser: includes inlined font-face styles and static loading page styles - critical (render blocking) - Browser->>Browser: define injection points - Browser->>Browser: load static loading page styles - Browser->>Browser: load font-face styles - Browser->>legacy: load startup.js special route - legacy->>legacy: build startup.js from template - Note over legacy: inject theme settings and font sources - legacy->>Browser: startup.js - critical startup.js - Browser->>Browser: get theme preferences from local storage - Browser->>Browser: set global theme tag - Browser->>Browser: inject theme-specific loading page styles - Browser->>Browser: inject theme-specific font css vars - end - end - Browser->>Browser: render loading/error page
(with loaders hidden) - Browser->>legacy: load bootstrap.js special route - legacy->>legacy: build bootstrap.js from template - legacy->>Browser: bootstrap.js - critical bootstrap.js - Browser->>Browser: toggle visibility of errors/loaders - Browser->>Browser: get theme preferences from local storage - Browser->>core/server/core_app: load js bundles - core/server/core_app->>Browser: (React application) - Browser->>core/server/core_app: load theme-specific stylesheets
(base, OUI, KUI, legacy) - core/server/core_app->>Browser: themed css - end - end -``` - -### Loading - -`src/legacy/ui/ui_render/ui_render_mixin.js` via `src/legacy/ui/ui_render/bootstrap/template.js.hbs` and `src/legacy/ui/ui_render/bootstrap/app_bootstrap.js`. Aliased in `src/legacy/ui/ui_mixin.js`, called by `src/legacy/server/osd_server.js`. Called by `src/core/server/legacy/legacy_service.ts` via `src/core/server/server.ts` - -### Injected style tags - -1. `src/core/server/rendering/views/styles.tsx` - depends on dark/light mode and injects style tag in head -2. `src/core/server/rendering/views/fonts.tsx` - depends on theme version and injects font style tag in head -3. Monaco editor styles -4. Ace styles -5. Ace TM overrides -6. Ace error styles -6. Component styles - -### Styleshsheets loaded - -Each of the following are loaded in the browser by the [bootstrap script](/src/legacy/ui/ui_render/bootstrap/template.js.hbs) in this order. Currently, these are never unloaded. - -1. Monaco editor styles (e.g. [/packages/osd-ui-shared-deps/target/osd-ui-shared-deps.css](/packages/osd-ui-shared-deps/target/osd-ui-shared-deps.css)), packaged by [/packages/osd-ui-shared-deps/webpack.config.js](/packages/osd-ui-shared-deps/webpack.config.js). In theory, this file could include styles from other shared dependencies, but currently `osd-monaco` is the only package that exports styles. Note that these are the default, un-themed styles; theming of monaco editors is handled by [/src/plugins/opensearch_dashboards_react/public/code_editor/editor_theme.ts](/src/plugins/opensearch_dashboards_react/public/code_editor/editor_theme.ts). -2. Theme and mode-specific OUI styles (e.g. [](), compiled by `packages/osd-ui-shared-deps/webpack.config.js`). -3. Theme and mode-specific KUI styles (e.g. `packages/osd-ui-framework/src/kui_next_dark.scss`, compiled by `packages/osd-ui-framework/Gruntfile.js`). Separate stylesheets for each theme version/dark mode combo (colors). -4. Mode-specific legacy styles (e.g. [/src/core/server/core_app/assets/legacy_dark_theme.css](/src/core/server/core_app/assets/legacy_dark_theme.css)) - -Component styles are not loaded as stylesheets. - -## Current theme usage - -### JSON/JS Vars - -1. Defined by `packages/osd-ui-shared-deps/theme.ts` - 1. Used by `src/plugins/charts/public/static/color_maps/color_maps.ts` to set vis colors - 2. Used by `src/plugins/discover/public/application/components/chart/histogram/histogram.tsx` to define Discover histogram Elastic Chart styling - 3. Used by `src/plugins/maps_legacy/public/map/opensearch_dashboards_map.js` and `src/plugins/region_map/public/choropleth_layer.js` for minor map UI styling (line color, empty shade) - 4. Used by `src/plugins/vis_type_vega/public/data_model/vega_parser.ts` for Vega/Vega-Lite theming -2. Used by `src/plugins/vis_type_vislib/public/vislib/components/tooltip/tooltip.js` for tooltip spacing -3. Used by `src/plugins/expressions/public/react_expression_renderer.tsx` to define padding options. -4. Used by `src/core/server/rendering/views/theme.ts` to inject values into `src/core/server/rendering/views/styles.tsx` -5. Used (incorrectly) to style a badge color in `src/plugins/index_pattern_management/public/components/create_button/create_button.tsx` -6. Used by `src/plugins/opensearch_dashboards_react/public/code_editor/editor_theme.ts` to create Monaco theme styles diff --git a/src/core/public/osd_bootstrap.test.ts b/src/core/public/osd_bootstrap.test.ts index e4209b460f86..806841287bee 100644 --- a/src/core/public/osd_bootstrap.test.ts +++ b/src/core/public/osd_bootstrap.test.ts @@ -34,7 +34,6 @@ import { __osdBootstrap__ } from './'; describe('osd_bootstrap', () => { beforeAll(() => { const metadata = { - branding: { darkMode: 'true' }, i18n: { translationsUrl: 'http://localhost' }, vars: { apmConfig: null }, }; diff --git a/src/core/public/osd_bootstrap.ts b/src/core/public/osd_bootstrap.ts index ed64ed0bc2b5..f5571292b83a 100644 --- a/src/core/public/osd_bootstrap.ts +++ b/src/core/public/osd_bootstrap.ts @@ -38,11 +38,6 @@ export async function __osdBootstrap__() { document.querySelector('osd-injected-metadata')!.getAttribute('data')! ); - const globals: any = typeof window === 'undefined' ? {} : window; - const themeTag: string = globals.__osdThemeTag__ || ''; - - injectedMetadata.branding.darkMode = themeTag.endsWith('dark'); - let i18nError: Error | undefined; const apmSystem = new ApmSystem(injectedMetadata.vars.apmConfig, injectedMetadata.basePath); diff --git a/src/core/public/ui_settings/ui_settings_client.ts b/src/core/public/ui_settings/ui_settings_client.ts index 19637debf948..8a5701de6b39 100644 --- a/src/core/public/ui_settings/ui_settings_client.ts +++ b/src/core/public/ui_settings/ui_settings_client.ts @@ -58,13 +58,6 @@ export class UiSettingsClient implements IUiSettingsClient { this.defaults = cloneDeep(params.defaults); this.cache = defaultsDeep({}, this.defaults, cloneDeep(params.initialSettings)); - if ( - this.cache['theme:enableUserControl']?.userValue ?? - this.cache['theme:enableUserControl']?.value - ) { - this.cache = defaultsDeep(this.cache, this.getBrowserStoredSettings()); - } - params.done$.subscribe({ complete: () => { this.update$.complete(); @@ -180,28 +173,6 @@ You can use \`IUiSettingsClient.get("${key}", defaultValue)\`, which will just r return this.updateErrors$.asObservable(); } - private getBrowserStoredSettings() { - const uiSettingsJSON = window.localStorage.getItem('uiSettings') || '{}'; - try { - return JSON.parse(uiSettingsJSON); - } catch (error) { - this.updateErrors$.next(error); - } - return {}; - } - - private setBrowserStoredSettings(key: string, newVal: any) { - const oldSettings = this.getBrowserStoredSettings(); - const newSettings = cloneDeep(oldSettings); - if (newVal === null) { - delete newSettings[key]; - } else { - newSettings[key] = { userValue: newVal }; - } - window.localStorage.setItem(`uiSettings`, JSON.stringify(newSettings)); - return { settings: newSettings }; - } - private assertUpdateAllowed(key: string) { if (this.isOverridden(key)) { throw new Error( @@ -227,18 +198,8 @@ You can use \`IUiSettingsClient.get("${key}", defaultValue)\`, which will just r this.setLocally(key, newVal); try { - if ( - this.cache['theme:enableUserControl']?.userValue ?? - this.cache['theme:enableUserControl']?.value - ) { - const { settings } = this.cache[key]?.preferBrowserSetting - ? this.setBrowserStoredSettings(key, newVal) - : (await this.api.batchSet(key, newVal)) || {}; - this.cache = defaultsDeep({}, defaults, this.getBrowserStoredSettings(), settings); - } else { - const { settings } = (await this.api.batchSet(key, newVal)) || {}; - this.cache = defaultsDeep({}, defaults, settings); - } + const { settings } = await this.api.batchSet(key, newVal); + this.cache = defaultsDeep({}, defaults, settings); this.saved$.next({ key, newValue: newVal, oldValue: initialVal }); return true; } catch (error) { diff --git a/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap b/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap index 01c238783ce5..ad92d759a832 100644 --- a/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap +++ b/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap @@ -8,6 +8,7 @@ Object { "branding": Object { "applicationTitle": "OpenSearch Dashboards", "assetFolderUrl": "/mock-server-basepath/ui/default_branding", + "darkMode": false, "loadingLogo": Object {}, "logo": Object {}, "mark": Object {}, @@ -60,6 +61,7 @@ Object { "branding": Object { "applicationTitle": "OpenSearch Dashboards", "assetFolderUrl": "/mock-server-basepath/ui/default_branding", + "darkMode": false, "loadingLogo": Object {}, "logo": Object {}, "mark": Object {}, @@ -112,6 +114,7 @@ Object { "branding": Object { "applicationTitle": "OpenSearch Dashboards", "assetFolderUrl": "/mock-server-basepath/ui/default_branding", + "darkMode": true, "loadingLogo": Object {}, "logo": Object {}, "mark": Object {}, @@ -164,6 +167,7 @@ Object { "branding": Object { "applicationTitle": "OpenSearch Dashboards", "assetFolderUrl": "/mock-server-basepath/ui/default_branding", + "darkMode": true, "loadingLogo": Object {}, "logo": Object {}, "mark": Object {}, @@ -220,6 +224,7 @@ Object { "branding": Object { "applicationTitle": "OpenSearch Dashboards", "assetFolderUrl": "/ui/default_branding", + "darkMode": false, "loadingLogo": Object {}, "logo": Object {}, "mark": Object {}, @@ -272,6 +277,7 @@ Object { "branding": Object { "applicationTitle": "OpenSearch Dashboards", "assetFolderUrl": "/mock-server-basepath/ui/default_branding", + "darkMode": false, "loadingLogo": Object {}, "logo": Object {}, "mark": Object {}, @@ -324,6 +330,7 @@ Object { "branding": Object { "applicationTitle": "OpenSearch Dashboards", "assetFolderUrl": "/mock-server-basepath/ui/default_branding", + "darkMode": false, "loadingLogo": Object {}, "logo": Object {}, "mark": Object {}, diff --git a/src/core/server/rendering/rendering_service.tsx b/src/core/server/rendering/rendering_service.tsx index 6030db2fd873..acaee7f42bc5 100644 --- a/src/core/server/rendering/rendering_service.tsx +++ b/src/core/server/rendering/rendering_service.tsx @@ -95,8 +95,20 @@ export class RenderingService { defaults: uiSettings.getRegistered(), user: includeUserSettings ? await uiSettings.getUserProvided() : {}, }; + // Cannot use `uiSettings.get()` since a user might not be authenticated + const darkMode = + (settings.user?.['theme:darkMode']?.userValue ?? + uiSettings.getOverrideOrDefault('theme:darkMode')) || + false; + + // At the very least, the schema should define a default theme; the '' will be unreachable + const themeVersion = + (settings.user?.['theme:version']?.userValue ?? + uiSettings.getOverrideOrDefault('theme:version')) || + ''; const brandingAssignment = await this.assignBrandingConfig( + darkMode, opensearchDashboardsConfig as OpenSearchDashboardsConfigType ); @@ -104,9 +116,10 @@ export class RenderingService { strictCsp: http.csp.strict, uiPublicUrl, bootstrapScriptUrl: `${basePath}/bootstrap.js`, - startupScriptUrl: `${basePath}/startup.js`, i18n: i18n.translate, locale: i18n.getLocale(), + darkMode, + themeVersion, injectedMetadata: { version: env.packageInfo.version, buildNumber: env.packageInfo.buildNum, @@ -131,6 +144,7 @@ export class RenderingService { uiSettings: settings, }, branding: { + darkMode, assetFolderUrl: `${uiPublicUrl}/default_branding`, logo: { defaultUrl: brandingAssignment.logoDefault, @@ -184,16 +198,20 @@ export class RenderingService { /** * Assign values for branding related configurations based on branding validation - * by calling checkBrandingValid(). If URL is valid, pass in + * by calling checkBrandingValid(). For dark mode URLs, add additional validation + * to see if there is a valid default mode URL exist first. If URL is valid, pass in * the actual URL; if not, pass in undefined. * + * @param {boolean} darkMode * @param {Readonly} opensearchDashboardsConfig * @returns {BrandingAssignment} valid URLs or undefined assigned for each branding configs */ private assignBrandingConfig = async ( + darkMode: boolean, opensearchDashboardsConfig: Readonly ): Promise => { const brandingValidation: BrandingValidation = await this.checkBrandingValid( + darkMode, opensearchDashboardsConfig ); const branding = opensearchDashboardsConfig.branding; @@ -212,18 +230,47 @@ export class RenderingService { : undefined; // assign dark mode URLs based on brandingValidation function result - const logoDarkmode = brandingValidation.isLogoDarkmodeValid + let logoDarkmode = brandingValidation.isLogoDarkmodeValid ? branding.logo.darkModeUrl : undefined; - const markDarkmode = brandingValidation.isMarkDarkmodeValid + let markDarkmode = brandingValidation.isMarkDarkmodeValid ? branding.mark.darkModeUrl : undefined; - const loadingLogoDarkmode = brandingValidation.isLoadingLogoDarkmodeValid + let loadingLogoDarkmode = brandingValidation.isLoadingLogoDarkmodeValid ? branding.loadingLogo.darkModeUrl : undefined; + /** + * For dark mode URLs, we added another validation: + * user can only provide a dark mode URL after providing a valid default mode URL, + * If user provides a valid dark mode URL but fails to provide a valid default mode URL, + * return undefined for the dark mode URL + */ + if (logoDarkmode && !logoDefault) { + this.logger + .get('branding') + .error('Must provide a valid logo default mode URL before providing a logo dark mode URL'); + logoDarkmode = undefined; + } + + if (markDarkmode && !markDefault) { + this.logger + .get('branding') + .error('Must provide a valid mark default mode URL before providing a mark dark mode URL'); + markDarkmode = undefined; + } + + if (loadingLogoDarkmode && !loadingLogoDefault) { + this.logger + .get('branding') + .error( + 'Must provide a valid loading logo default mode URL before providing a loading logo dark mode URL' + ); + loadingLogoDarkmode = undefined; + } + // assign favicon based on brandingValidation function result const favicon = brandingValidation.isFaviconValid ? branding.faviconUrl : undefined; @@ -255,30 +302,35 @@ export class RenderingService { * user inputs valid or invalid URLs by calling isUrlValid() function. Also * check if title is valid by calling isTitleValid() function. * + * @param {boolean} darkMode * @param {Readonly} opensearchDashboardsConfig * @returns {BrandingValidation} indicate valid/invalid URL for each branding config */ private checkBrandingValid = async ( + darkMode: boolean, opensearchDashboardsConfig: Readonly ): Promise => { const branding = opensearchDashboardsConfig.branding; const isLogoDefaultValid = await this.isUrlValid(branding.logo.defaultUrl, 'logo default'); - const isLogoDarkmodeValid = await this.isUrlValid(branding.logo.darkModeUrl, 'logo darkMode'); + const isLogoDarkmodeValid = darkMode + ? await this.isUrlValid(branding.logo.darkModeUrl, 'logo darkMode') + : false; const isMarkDefaultValid = await this.isUrlValid(branding.mark.defaultUrl, 'mark default'); - const isMarkDarkmodeValid = await this.isUrlValid(branding.mark.darkModeUrl, 'mark darkMode'); + const isMarkDarkmodeValid = darkMode + ? await this.isUrlValid(branding.mark.darkModeUrl, 'mark darkMode') + : false; const isLoadingLogoDefaultValid = await this.isUrlValid( branding.loadingLogo.defaultUrl, 'loadingLogo default' ); - const isLoadingLogoDarkmodeValid = await this.isUrlValid( - branding.loadingLogo.darkModeUrl, - 'loadingLogo darkMode' - ); + const isLoadingLogoDarkmodeValid = darkMode + ? await this.isUrlValid(branding.loadingLogo.darkModeUrl, 'loadingLogo darkMode') + : false; const isFaviconValid = await this.isUrlValid(branding.faviconUrl, 'favicon'); diff --git a/src/core/server/rendering/types.ts b/src/core/server/rendering/types.ts index ecf3e2a9674e..45821c2b8228 100644 --- a/src/core/server/rendering/types.ts +++ b/src/core/server/rendering/types.ts @@ -43,9 +43,10 @@ export interface RenderingMetadata { strictCsp: ICspConfig['strict']; uiPublicUrl: string; bootstrapScriptUrl: string; - startupScriptUrl: string; i18n: typeof i18n.translate; locale: string; + darkMode: boolean; + themeVersion: string; injectedMetadata: { version: string; buildNumber: number; diff --git a/src/core/server/rendering/views/__snapshots__/template.test.tsx.snap b/src/core/server/rendering/views/__snapshots__/template.test.tsx.snap index 1204752a6469..36d073992ec8 100644 --- a/src/core/server/rendering/views/__snapshots__/template.test.tsx.snap +++ b/src/core/server/rendering/views/__snapshots__/template.test.tsx.snap @@ -50,6 +50,10 @@ Array [ content="[object Object]/ui/favicons/browserconfig.xml" name="msapplication-config" />, + , null, , null, - , - + + + + \ No newline at end of file diff --git a/docs/openapi/index_patterns/index_patterns.yml b/docs/openapi/index_patterns/index_patterns.yml new file mode 100644 index 000000000000..7a20e5bf4862 --- /dev/null +++ b/docs/openapi/index_patterns/index_patterns.yml @@ -0,0 +1,83 @@ +openapi: 3.0.3 +info: + version: v1 + title: OpenSearch Dashboards Index Patterns API + contact: + name: OpenSearch Dashboards Team + description: |- + OpenAPI schema for OpenSearch Dashboards Index Patterns API +tags: + - name: index patterns +paths: + /api/index_patterns/_fields_for_wildcard: + get: + tags: + - index patterns + summary: + parameters: + - in: query + name: pattern + description: The index pattern used to retrieve fields. + required: true + schema: + type: string + example: my-index* + - in: query + name: meta_fields + description: The list of metadata fields which will be included in the response, it usually contains "_source", "_id", "_type", "_index" and "_score". + schema: + oneOf: + - type: string + - type: array + default: [] + example: _source + - in: query + name: data_source + description: The data source of index patterns and indices. + schema: + type: string + responses: + '200': + description: Fetching fields for index pattern is successful. + content: + application/json: + schema: + type: object + properties: + fields: + type: array + description: Retrieved fields based on wildcard pattern. + items: + type: object + '400': + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/400_bad_request' + '404': + description: Not found + content: + application/json: + schema: + type: object +components: + schemas: + 400_bad_request: + title: Bad request + type: object + required: + - error + - message + - statusCode + properties: + error: + type: string + enum: + - Bad Request + message: + type: string + statusCode: + type: integer + enum: + - 400 \ No newline at end of file From e751b695e284b06b01b7f1560d13b8944a7fef3b Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:29:06 +0800 Subject: [PATCH 069/276] [navigation-next] Add new category (#7275) (#7276) (#7278) * feat: add new categories * Changeset file for PR #7273 created/updated * feat: update * Changeset file for PR #7275 created/updated * feat: remove useless changelog * feat: remove useless changelog --------- (cherry picked from commit 84537b58845d0a15fb2553978493c56b20c2ea3a) (cherry picked from commit d2e7b9d41cf1725b49eb5826c0673d2bb1609d24) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7275.yml | 2 ++ src/core/utils/default_app_categories.ts | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 changelogs/fragments/7275.yml diff --git a/changelogs/fragments/7275.yml b/changelogs/fragments/7275.yml new file mode 100644 index 000000000000..5ab63b119edf --- /dev/null +++ b/changelogs/fragments/7275.yml @@ -0,0 +1,2 @@ +feat: +- [navigation-next] Add new category ([#7275](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7275)) \ No newline at end of file diff --git a/src/core/utils/default_app_categories.ts b/src/core/utils/default_app_categories.ts index e0b748021199..49277b894d12 100644 --- a/src/core/utils/default_app_categories.ts +++ b/src/core/utils/default_app_categories.ts @@ -81,9 +81,16 @@ export const DEFAULT_APP_CATEGORIES: Record = Object.freeze order: 1000, }, dashboardAndReport: { - id: 'dashboardAndReport', - label: i18n.translate('core.ui.dashboardAndReport.label', { - defaultMessage: 'Dashboard and report', + id: 'visualizeAndReport', + label: i18n.translate('core.ui.visualizeAndReport.label', { + defaultMessage: 'Visualize and report', + }), + order: 2000, + }, + visualizeAndReport: { + id: 'visualizeAndReport', + label: i18n.translate('core.ui.visualizeAndReport.label', { + defaultMessage: 'Visualize and report', }), order: 2000, }, @@ -94,4 +101,11 @@ export const DEFAULT_APP_CATEGORIES: Record = Object.freeze }), order: 4000, }, + detect: { + id: 'detect', + label: i18n.translate('core.ui.detect.label', { + defaultMessage: 'Detect', + }), + order: 3000, + }, }); From 42140cabdba3c6c89b1e32a4c82e95b5fb283bad Mon Sep 17 00:00:00 2001 From: Tianyu Gao Date: Wed, 17 Jul 2024 18:15:00 +0800 Subject: [PATCH 070/276] [Workspace] [Data Source] feat: support workspace level default data source (#7188) (#7281) * feat: support set default ds in workspace Signed-off-by: tygao * add updateWorkspaceState Signed-off-by: tygao * Changeset file for PR #7188 created/updated * update workspace plugin test Signed-off-by: tygao * add reset workspace state and update tests Signed-off-by: tygao * update and add tests for workspace client Signed-off-by: tygao * clear default data source if no data source left and seperate wrapper Signed-off-by: tygao * add try catch and add tests Signed-off-by: tygao * disable DSM in workspace Signed-off-by: tygao --------- Signed-off-by: tygao Signed-off-by: Tianyu Gao Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: Yulong Ruan (cherry picked from commit e1d50967b2a707107240b49634fb00e4b919152e) --- changelogs/fragments/7188.yml | 2 + .../data_source_management/common/index.ts | 1 + .../public/components/constants.tsx | 2 +- .../data_source_management/public/plugin.ts | 1 - src/plugins/workspace/server/plugin.ts | 3 +- ...rkspace_ui_settings_client_wrapper.test.ts | 6 +- .../workspace_ui_settings_client_wrapper.ts | 6 ++ src/plugins/workspace/server/types.ts | 8 ++ src/plugins/workspace/server/utils.test.ts | 51 ++++++++++++ src/plugins/workspace/server/utils.ts | 24 ++++++ .../workspace/server/workspace_client.test.ts | 80 +++++++++++++++---- .../workspace/server/workspace_client.ts | 40 +++++++++- 12 files changed, 200 insertions(+), 24 deletions(-) create mode 100644 changelogs/fragments/7188.yml diff --git a/changelogs/fragments/7188.yml b/changelogs/fragments/7188.yml new file mode 100644 index 000000000000..3582b5d6feef --- /dev/null +++ b/changelogs/fragments/7188.yml @@ -0,0 +1,2 @@ +feat: +- Support workspace level default data source ([#7188](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7188)) \ No newline at end of file diff --git a/src/plugins/data_source_management/common/index.ts b/src/plugins/data_source_management/common/index.ts index 3ba84084699a..980bf8939456 100644 --- a/src/plugins/data_source_management/common/index.ts +++ b/src/plugins/data_source_management/common/index.ts @@ -5,3 +5,4 @@ export const PLUGIN_ID = 'dataSourceManagement'; export const PLUGIN_NAME = 'Data sources'; +export const DEFAULT_DATA_SOURCE_UI_SETTINGS_ID = 'defaultDataSource'; diff --git a/src/plugins/data_source_management/public/components/constants.tsx b/src/plugins/data_source_management/public/components/constants.tsx index 23a71ec45ed0..bfb720980132 100644 --- a/src/plugins/data_source_management/public/components/constants.tsx +++ b/src/plugins/data_source_management/public/components/constants.tsx @@ -18,4 +18,4 @@ export const CONNECT_DATASOURCES_MESSAGE = 'Connect your data sources to get sta export const NO_COMPATIBLE_DATASOURCES_MESSAGE = 'No compatible data sources are available.'; export const ADD_COMPATIBLE_DATASOURCES_MESSAGE = 'Add a compatible data source.'; -export const DEFAULT_DATA_SOURCE_UI_SETTINGS_ID = 'defaultDataSource'; +export { DEFAULT_DATA_SOURCE_UI_SETTINGS_ID } from '../../common'; diff --git a/src/plugins/data_source_management/public/plugin.ts b/src/plugins/data_source_management/public/plugin.ts index a371936b8ee7..dbbe22cf48ed 100644 --- a/src/plugins/data_source_management/public/plugin.ts +++ b/src/plugins/data_source_management/public/plugin.ts @@ -52,7 +52,6 @@ export interface DataSourceManagementPluginStart { getAuthenticationMethodRegistry: () => IAuthenticationMethodRegistry; } -// src/plugins/workspace/public/plugin.ts Workspace depends on this ID and hard code to avoid adding dependency on DSM bundle. export const DSM_APP_ID = 'dataSources'; export class DataSourceManagementPlugin diff --git a/src/plugins/workspace/server/plugin.ts b/src/plugins/workspace/server/plugin.ts index 1081284b7d9e..eed42fb85636 100644 --- a/src/plugins/workspace/server/plugin.ts +++ b/src/plugins/workspace/server/plugin.ts @@ -113,7 +113,7 @@ export class WorkspacePlugin implements Plugin { type: 'config', attributes: { defaultIndex: 'default-index-global', + [DEFAULT_DATA_SOURCE_UI_SETTINGS_ID]: 'default-ds-global', }, }); } else if (type === WORKSPACE_TYPE) { @@ -59,7 +61,7 @@ describe('WorkspaceUiSettingsClientWrapper', () => { }; }; - it('should return workspace ui settings if in a workspace', async () => { + it('should return workspace ui settings and should return workspace default data source and not extend global if in a workspace', async () => { // Currently in a workspace jest.spyOn(utils, 'getWorkspaceState').mockReturnValue({ requestWorkspaceId: 'workspace-id' }); @@ -72,6 +74,7 @@ describe('WorkspaceUiSettingsClientWrapper', () => { type: 'config', attributes: { defaultIndex: 'default-index-workspace', + [DEFAULT_DATA_SOURCE_UI_SETTINGS_ID]: undefined, }, }); }); @@ -89,6 +92,7 @@ describe('WorkspaceUiSettingsClientWrapper', () => { type: 'config', attributes: { defaultIndex: 'default-index-global', + [DEFAULT_DATA_SOURCE_UI_SETTINGS_ID]: 'default-ds-global', }, }); }); diff --git a/src/plugins/workspace/server/saved_objects/workspace_ui_settings_client_wrapper.ts b/src/plugins/workspace/server/saved_objects/workspace_ui_settings_client_wrapper.ts index 9cc860ec903e..52cccc6a01c0 100644 --- a/src/plugins/workspace/server/saved_objects/workspace_ui_settings_client_wrapper.ts +++ b/src/plugins/workspace/server/saved_objects/workspace_ui_settings_client_wrapper.ts @@ -18,6 +18,7 @@ import { } from '../../../../core/server'; import { WORKSPACE_UI_SETTINGS_CLIENT_WRAPPER_ID } from '../../common/constants'; import { Logger } from '../../../../core/server'; +import { DEFAULT_DATA_SOURCE_UI_SETTINGS_ID } from '../../../data_source_management/common'; /** * This saved object client wrapper offers methods to get and update UI settings considering @@ -73,9 +74,14 @@ export class WorkspaceUiSettingsClientWrapper { this.logger.error(`Unable to get workspaceObject with id: ${requestWorkspaceId}`); } + const workspaceLevelDefaultDS = + workspaceObject?.attributes?.uiSettings?.[DEFAULT_DATA_SOURCE_UI_SETTINGS_ID]; + configObject.attributes = { ...configObject.attributes, ...(workspaceObject ? workspaceObject.attributes.uiSettings : {}), + // Workspace level default data source value should not extend global UIsettings value. + [DEFAULT_DATA_SOURCE_UI_SETTINGS_ID]: workspaceLevelDefaultDS, }; return configObject as SavedObject; diff --git a/src/plugins/workspace/server/types.ts b/src/plugins/workspace/server/types.ts index 703df213bc84..82d4bc594a7e 100644 --- a/src/plugins/workspace/server/types.ts +++ b/src/plugins/workspace/server/types.ts @@ -12,6 +12,7 @@ import { WorkspaceAttribute, SavedObjectsServiceStart, Permissions, + UiSettingsServiceStart, } from '../../../core/server'; export interface WorkspaceAttributeWithPermission extends WorkspaceAttribute { @@ -48,6 +49,13 @@ export interface IWorkspaceClientImpl { * @public */ setSavedObjects(savedObjects: SavedObjectsServiceStart): void; + /** + * Set ui settings client that will be used inside the workspace client. + * @param uiSettings {@link UiSettingsServiceStart} + * @returns void + * @public + */ + setUiSettings(uiSettings: UiSettingsServiceStart): void; /** * Create a workspace * @param requestDetail {@link IRequestDetail} diff --git a/src/plugins/workspace/server/utils.test.ts b/src/plugins/workspace/server/utils.test.ts index 95db93e5b97a..ba7532c216eb 100644 --- a/src/plugins/workspace/server/utils.test.ts +++ b/src/plugins/workspace/server/utils.test.ts @@ -8,6 +8,7 @@ import { httpServerMock, httpServiceMock, savedObjectsClientMock, + uiSettingsServiceMock, } from '../../../core/server/mocks'; import { generateRandomId, @@ -16,9 +17,11 @@ import { updateDashboardAdminStateForRequest, transferCurrentUserInPermissions, getDataSourcesList, + checkAndSetDefaultDataSource, } from './utils'; import { getWorkspaceState } from '../../../core/server/utils'; import { Observable, of } from 'rxjs'; +import { DEFAULT_DATA_SOURCE_UI_SETTINGS_ID } from '../../data_source_management/common'; describe('workspace utils', () => { const mockAuth = httpServiceMock.createAuth(); @@ -205,4 +208,52 @@ describe('workspace utils', () => { const result = await getDataSourcesList(savedObjectsClient, []); expect(result).toEqual([]); }); + + it('should set first data sources as default when not need check', async () => { + const savedObjectsClient = savedObjectsClientMock.create(); + const uiSettings = uiSettingsServiceMock.createStartContract(); + const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); + const dataSources = ['id1', 'id2']; + await checkAndSetDefaultDataSource(uiSettingsClient, dataSources, false); + expect(uiSettingsClient.set).toHaveBeenCalledWith( + DEFAULT_DATA_SOURCE_UI_SETTINGS_ID, + dataSources[0] + ); + }); + + it('should not set default data source after checking if not needed', async () => { + const savedObjectsClient = savedObjectsClientMock.create(); + const uiSettings = uiSettingsServiceMock.createStartContract(); + const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); + const dataSources = ['id1', 'id2']; + uiSettingsClient.get = jest.fn().mockResolvedValue(dataSources[0]); + await checkAndSetDefaultDataSource(uiSettingsClient, dataSources, true); + expect(uiSettingsClient.set).not.toBeCalled(); + }); + + it('should check then set first data sources as default if needed when checking', async () => { + const savedObjectsClient = savedObjectsClientMock.create(); + const uiSettings = uiSettingsServiceMock.createStartContract(); + const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); + const dataSources = ['id1', 'id2']; + uiSettingsClient.get = jest.fn().mockResolvedValue(''); + await checkAndSetDefaultDataSource(uiSettingsClient, dataSources, true); + expect(uiSettingsClient.set).toHaveBeenCalledWith( + DEFAULT_DATA_SOURCE_UI_SETTINGS_ID, + dataSources[0] + ); + }); + + it('should clear default data source if there is no new data source', async () => { + const savedObjectsClient = savedObjectsClientMock.create(); + const uiSettings = uiSettingsServiceMock.createStartContract(); + const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); + const dataSources: string[] = []; + uiSettingsClient.get = jest.fn().mockResolvedValue(''); + await checkAndSetDefaultDataSource(uiSettingsClient, dataSources, true); + expect(uiSettingsClient.set).toHaveBeenCalledWith( + DEFAULT_DATA_SOURCE_UI_SETTINGS_ID, + undefined + ); + }); }); diff --git a/src/plugins/workspace/server/utils.ts b/src/plugins/workspace/server/utils.ts index f48c78f9a5dd..9f144c7eb1c3 100644 --- a/src/plugins/workspace/server/utils.ts +++ b/src/plugins/workspace/server/utils.ts @@ -15,9 +15,11 @@ import { SharedGlobalConfig, Permissions, SavedObjectsClientContract, + IUiSettingsClient, } from '../../../core/server'; import { AuthInfo } from './types'; import { updateWorkspaceState } from '../../../core/server/utils'; +import { DEFAULT_DATA_SOURCE_UI_SETTINGS_ID } from '../../data_source_management/common'; import { CURRENT_USER_PLACEHOLDER } from '../common/constants'; /** @@ -136,3 +138,25 @@ export const getDataSourcesList = (client: SavedObjectsClientContract, workspace } }); }; + +export const checkAndSetDefaultDataSource = async ( + uiSettingsClient: IUiSettingsClient, + dataSources: string[], + needCheck: boolean +) => { + if (dataSources?.length > 0) { + if (!needCheck) { + // Create# Will set first data source as default data source. + await uiSettingsClient.set(DEFAULT_DATA_SOURCE_UI_SETTINGS_ID, dataSources[0]); + } else { + // Update will check if default DS still exists. + const defaultDSId = (await uiSettingsClient.get(DEFAULT_DATA_SOURCE_UI_SETTINGS_ID)) ?? ''; + if (!dataSources.includes(defaultDSId)) { + await uiSettingsClient.set(DEFAULT_DATA_SOURCE_UI_SETTINGS_ID, dataSources[0]); + } + } + } else { + // If there is no data source left, clear workspace level default data source. + await uiSettingsClient.set(DEFAULT_DATA_SOURCE_UI_SETTINGS_ID, undefined); + } +}; diff --git a/src/plugins/workspace/server/workspace_client.test.ts b/src/plugins/workspace/server/workspace_client.test.ts index 7d1d692e2e4d..208def26ad02 100644 --- a/src/plugins/workspace/server/workspace_client.test.ts +++ b/src/plugins/workspace/server/workspace_client.test.ts @@ -5,15 +5,22 @@ import { WorkspaceClient } from './workspace_client'; -import { coreMock, httpServerMock } from '../../../core/server/mocks'; +import { + coreMock, + httpServerMock, + uiSettingsServiceMock, + loggingSystemMock, +} from '../../../core/server/mocks'; import { DATA_SOURCE_SAVED_OBJECT_TYPE } from '../../data_source/common'; -import { SavedObjectsServiceStart } from '../../../core/server'; +import { SavedObjectsServiceStart, SavedObjectsClientContract } from '../../../core/server'; import { IRequestDetail } from './types'; const coreSetup = coreMock.createSetup(); const mockWorkspaceId = 'workspace_id'; const mockWorkspaceName = 'workspace_name'; +const mockCheckAndSetDefaultDataSource = jest.fn(); +const logger = loggingSystemMock.create().get(); jest.mock('./utils', () => ({ generateRandomId: () => mockWorkspaceId, @@ -25,6 +32,7 @@ jest.mock('./utils', () => ({ id: 'id2', }, ]), + checkAndSetDefaultDataSource: (...args) => mockCheckAndSetDefaultDataSource(...args), })); describe('#WorkspaceClient', () => { @@ -35,20 +43,24 @@ describe('#WorkspaceClient', () => { const find = jest.fn(); const addToWorkspaces = jest.fn(); const deleteFromWorkspaces = jest.fn(); + const savedObjectClient = ({ + find, + addToWorkspaces, + deleteFromWorkspaces, + create: jest.fn(), + get: jest.fn().mockResolvedValue({ + attributes: { + name: mockWorkspaceName, + }, + }), + } as unknown) as SavedObjectsClientContract; const savedObjects = ({ ...coreSetup.savedObjects, - getScopedClient: () => ({ - find, - addToWorkspaces, - deleteFromWorkspaces, - get: jest.fn().mockResolvedValue({ - attributes: { - name: mockWorkspaceName, - }, - }), - }), + getScopedClient: () => savedObjectClient, } as unknown) as SavedObjectsServiceStart; + const uiSettings = uiSettingsServiceMock.createStartContract(); + const mockRequestDetail = ({ request: httpServerMock.createOpenSearchDashboardsRequest(), context: coreMock.createRequestHandlerContext(), @@ -56,7 +68,7 @@ describe('#WorkspaceClient', () => { } as unknown) as IRequestDetail; it('create# should not call addToWorkspaces if no data sources passed', async () => { - const client = new WorkspaceClient(coreSetup); + const client = new WorkspaceClient(coreSetup, logger); await client.setup(coreSetup); client?.setSavedObjects(savedObjects); @@ -69,7 +81,7 @@ describe('#WorkspaceClient', () => { }); it('create# should call addToWorkspaces with passed data sources normally', async () => { - const client = new WorkspaceClient(coreSetup); + const client = new WorkspaceClient(coreSetup, logger); await client.setup(coreSetup); client?.setSavedObjects(savedObjects); @@ -84,8 +96,25 @@ describe('#WorkspaceClient', () => { ]); }); + it('create# should call set default data source after creating', async () => { + const client = new WorkspaceClient(coreSetup, logger); + await client.setup(coreSetup); + client?.setSavedObjects(savedObjects); + client?.setUiSettings(uiSettings); + + await client.create(mockRequestDetail, { + name: mockWorkspaceName, + permissions: {}, + dataSources: ['id1'], + }); + + const uiSettingsClient = uiSettings.asScopedToClient(savedObjectClient); + + expect(mockCheckAndSetDefaultDataSource).toHaveBeenCalledWith(uiSettingsClient, ['id1'], false); + }); + it('update# should not call addToWorkspaces if no new data sources added', async () => { - const client = new WorkspaceClient(coreSetup); + const client = new WorkspaceClient(coreSetup, logger); await client.setup(coreSetup); client?.setSavedObjects(savedObjects); @@ -99,7 +128,7 @@ describe('#WorkspaceClient', () => { }); it('update# should call deleteFromWorkspaces if there is data source to be removed', async () => { - const client = new WorkspaceClient(coreSetup); + const client = new WorkspaceClient(coreSetup, logger); await client.setup(coreSetup); client?.setSavedObjects(savedObjects); @@ -117,7 +146,7 @@ describe('#WorkspaceClient', () => { ]); }); it('update# should calculate data sources to be added and to be removed', async () => { - const client = new WorkspaceClient(coreSetup); + const client = new WorkspaceClient(coreSetup, logger); await client.setup(coreSetup); client?.setSavedObjects(savedObjects); @@ -134,4 +163,21 @@ describe('#WorkspaceClient', () => { mockWorkspaceId, ]); }); + + it('update# should call set default data source with check after updating', async () => { + const client = new WorkspaceClient(coreSetup, logger); + await client.setup(coreSetup); + client?.setSavedObjects(savedObjects); + client?.setUiSettings(uiSettings); + + await client.update(mockRequestDetail, mockWorkspaceId, { + name: mockWorkspaceName, + permissions: {}, + dataSources: ['id1'], + }); + + const uiSettingsClient = uiSettings.asScopedToClient(savedObjectClient); + + expect(mockCheckAndSetDefaultDataSource).toHaveBeenCalledWith(uiSettingsClient, ['id1'], true); + }); }); diff --git a/src/plugins/workspace/server/workspace_client.ts b/src/plugins/workspace/server/workspace_client.ts index ad9d81cb952c..159136e1304f 100644 --- a/src/plugins/workspace/server/workspace_client.ts +++ b/src/plugins/workspace/server/workspace_client.ts @@ -10,8 +10,11 @@ import { CoreSetup, WorkspaceAttribute, SavedObjectsServiceStart, + UiSettingsServiceStart, + WORKSPACE_TYPE, + Logger, } from '../../../core/server'; -import { WORKSPACE_TYPE } from '../../../core/server'; +import { updateWorkspaceState, getWorkspaceState } from '../../../core/server/utils'; import { IWorkspaceClientImpl, WorkspaceFindOptions, @@ -20,7 +23,7 @@ import { WorkspaceAttributeWithPermission, } from './types'; import { workspace } from './saved_objects'; -import { generateRandomId, getDataSourcesList } from './utils'; +import { generateRandomId, getDataSourcesList, checkAndSetDefaultDataSource } from './utils'; import { WORKSPACE_ID_CONSUMER_WRAPPER_ID, WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID, @@ -35,10 +38,13 @@ const DUPLICATE_WORKSPACE_NAME_ERROR = i18n.translate('workspace.duplicate.name. export class WorkspaceClient implements IWorkspaceClientImpl { private setupDep: CoreSetup; + private logger: Logger; private savedObjects?: SavedObjectsServiceStart; + private uiSettings?: UiSettingsServiceStart; - constructor(core: CoreSetup) { + constructor(core: CoreSetup, logger: Logger) { this.setupDep = core; + this.logger = logger; } private getScopedClientWithoutPermission( @@ -122,6 +128,25 @@ export class WorkspaceClient implements IWorkspaceClientImpl { permissions, } ); + if (dataSources && this.uiSettings && client) { + const rawState = getWorkspaceState(requestDetail.request); + // This is for setting in workspace environment, otherwise uiSettings can't set workspace level value. + updateWorkspaceState(requestDetail.request, { + requestWorkspaceId: id, + }); + // Set first data source as default after creating workspace + const uiSettingsClient = this.uiSettings.asScopedToClient(client); + try { + await checkAndSetDefaultDataSource(uiSettingsClient, dataSources, false); + } catch (e) { + this.logger.error('Set default data source error'); + } finally { + // Reset workspace state + updateWorkspaceState(requestDetail.request, { + requestWorkspaceId: rawState.requestWorkspaceId, + }); + } + } return { success: true, @@ -248,6 +273,12 @@ export class WorkspaceClient implements IWorkspaceClientImpl { version: workspaceInDB.version, } ); + + if (newDataSources && this.uiSettings && client) { + const uiSettingsClient = this.uiSettings.asScopedToClient(client); + checkAndSetDefaultDataSource(uiSettingsClient, newDataSources, true); + } + return { success: true, result: true, @@ -292,6 +323,9 @@ export class WorkspaceClient implements IWorkspaceClientImpl { public setSavedObjects(savedObjects: SavedObjectsServiceStart) { this.savedObjects = savedObjects; } + public setUiSettings(uiSettings: UiSettingsServiceStart) { + this.uiSettings = uiSettings; + } public async destroy(): Promise> { return { success: true, From bb595dd79f2951a15edb939bafa8b58f4afcd06a Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:43:16 -0700 Subject: [PATCH 071/276] [Look&Feel] apply pattern guidance to Dashboards (#7277) (#7287) (cherry picked from commit 6d6ffaab14970c147651186957aa962cee9be06c) Signed-off-by: Zhongnan Su Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../add_panel/add_panel_flyout.tsx | 6 +- .../panel/panel_header/panel_options_menu.tsx | 1 + .../__snapshots__/indices_list.test.tsx.snap | 5 ++ .../share_context_menu.test.tsx.snap | 6 +- .../__snapshots__/new_vis_modal.test.tsx.snap | 60 ++++++++++++++----- .../wizard/type_selection/type_selection.tsx | 13 ++-- 6 files changed, 67 insertions(+), 24 deletions(-) diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx index 473424984c2f..1b1aa65225b1 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.tsx @@ -33,7 +33,7 @@ import { FormattedMessage } from '@osd/i18n/react'; import React, { ReactElement } from 'react'; import { CoreSetup } from 'src/core/public'; -import { EuiContextMenuItem, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; +import { EuiContextMenuItem, EuiFlyoutBody, EuiFlyoutHeader, EuiText } from '@elastic/eui'; import { EmbeddableStart } from 'src/plugins/embeddable/public'; import { IContainer } from '../../../../containers'; @@ -163,11 +163,11 @@ export class AddPanelFlyout extends React.Component { return ( <> - +

-
+
{savedObjectsFinder} diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_options_menu.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_options_menu.tsx index 66dd676e8040..d9582214034e 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_options_menu.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_options_menu.tsx @@ -128,6 +128,7 @@ export class PanelOptionsMenu extends React.Component ); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/__snapshots__/indices_list.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/__snapshots__/indices_list.test.tsx.snap index aaba80f050c7..5eef8fd09f9c 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/__snapshots__/indices_list.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/__snapshots__/indices_list.test.tsx.snap @@ -94,6 +94,7 @@ exports[`IndicesList should change pages 1`] = ` , ] } + size="s" /> @@ -187,6 +188,7 @@ exports[`IndicesList should change per page 1`] = ` , ] } + size="s" /> @@ -297,6 +299,7 @@ exports[`IndicesList should highlight the query in the matches 1`] = ` , ] } + size="s" /> @@ -398,6 +401,7 @@ exports[`IndicesList should render normally 1`] = ` , ] } + size="s" /> @@ -563,6 +567,7 @@ exports[`IndicesList updating props should render all new indices 1`] = ` , ] } + size="s" /> diff --git a/src/plugins/share/public/components/__snapshots__/share_context_menu.test.tsx.snap b/src/plugins/share/public/components/__snapshots__/share_context_menu.test.tsx.snap index 95d3026f66d3..32cef3fcec57 100644 --- a/src/plugins/share/public/components/__snapshots__/share_context_menu.test.tsx.snap +++ b/src/plugins/share/public/components/__snapshots__/share_context_menu.test.tsx.snap @@ -55,7 +55,7 @@ exports[`shareContextMenuExtensions should sort ascending on sort order first an }, ] } - size="m" + size="s" /> `; @@ -79,7 +79,7 @@ exports[`should only render permalink panel when there are no other panels 1`] = }, ] } - size="m" + size="s" /> `; @@ -132,7 +132,7 @@ exports[`should render context menu panel when there are more than one panel 1`] }, ] } - size="m" + size="s" /> `; diff --git a/src/plugins/visualizations/public/wizard/__snapshots__/new_vis_modal.test.tsx.snap b/src/plugins/visualizations/public/wizard/__snapshots__/new_vis_modal.test.tsx.snap index d3501fc655ac..6b40556c74cf 100644 --- a/src/plugins/visualizations/public/wizard/__snapshots__/new_vis_modal.test.tsx.snap +++ b/src/plugins/visualizations/public/wizard/__snapshots__/new_vis_modal.test.tsx.snap @@ -175,7 +175,13 @@ exports[`NewVisModal filter for visualization types should render as expected 1`
- New Visualization +
+

+ New Visualization +

+
- - New Visualization - +
+

+ + New Visualization + +

+
+
@@ -1296,7 +1312,13 @@ exports[`NewVisModal should render as expected 1`] = `
- New Visualization +
+

+ New Visualization +

+
- - New Visualization - +
+

+ + New Visualization + +

+
+
diff --git a/src/plugins/visualizations/public/wizard/type_selection/type_selection.tsx b/src/plugins/visualizations/public/wizard/type_selection/type_selection.tsx index 6c5449e0e1ac..9f4e5f66e6c2 100644 --- a/src/plugins/visualizations/public/wizard/type_selection/type_selection.tsx +++ b/src/plugins/visualizations/public/wizard/type_selection/type_selection.tsx @@ -43,6 +43,7 @@ import { EuiModalHeaderTitle, EuiScreenReaderOnly, EuiSpacer, + EuiText, EuiTitle, } from '@elastic/eui'; @@ -96,10 +97,14 @@ class TypeSelection extends React.Component - + +

+ +

+
From e5b6bcef82dd73396262f74cc20cb10b11b510e4 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:44:01 -0700 Subject: [PATCH 072/276] [Look&Feel] Use small EuiTabs and EuiTabbedContent across the board (#7232) (#7255) * [Look&Feel] Use small EuiTabs and EuiTabbedContent across the board * Changeset file for PR #7232 created/updated --------- (cherry picked from commit 9893ce110758422df863cd463306cd19560f08fd) Signed-off-by: Zhongnan Su Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7232.yml | 2 ++ src/plugins/dev_tools/public/application.tsx | 2 +- .../doc_viewer/__snapshots__/doc_viewer.test.tsx.snap | 1 + .../public/application/components/doc_viewer/doc_viewer.tsx | 2 +- .../home/public/application/components/feature_directory.js | 4 +++- .../home/public/application/components/tutorial_directory.js | 2 +- .../public/components/edit_index_pattern/tabs/tabs.tsx | 1 + .../scripting_help/__snapshots__/help_flyout.test.tsx.snap | 2 ++ .../field_editor/components/scripting_help/help_flyout.tsx | 2 +- .../public/application/components/vis_picker.js | 2 +- 10 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/7232.yml diff --git a/changelogs/fragments/7232.yml b/changelogs/fragments/7232.yml new file mode 100644 index 000000000000..269905919d25 --- /dev/null +++ b/changelogs/fragments/7232.yml @@ -0,0 +1,2 @@ +refactor: +- [Look&Feel] Use small EuiTabs and EuiTabbedContent across the board ([#7232](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7232)) \ No newline at end of file diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx index 569c4b82a7dd..b1ccd290e59a 100644 --- a/src/plugins/dev_tools/public/application.tsx +++ b/src/plugins/dev_tools/public/application.tsx @@ -131,7 +131,7 @@ function DevToolsWrapper({ return (
- + {devTools.map((currentDevTool) => ( with 3 different tabs 1`] = ` > - +
); } diff --git a/src/plugins/home/public/application/components/feature_directory.js b/src/plugins/home/public/application/components/feature_directory.js index a82a15cdff96..9214fcb6c8a8 100644 --- a/src/plugins/home/public/application/components/feature_directory.js +++ b/src/plugins/home/public/application/components/feature_directory.js @@ -149,7 +149,9 @@ export class FeatureDirectory extends React.Component { - {this.renderTabs()} + + {this.renderTabs()} + {this.renderDirectories()} diff --git a/src/plugins/home/public/application/components/tutorial_directory.js b/src/plugins/home/public/application/components/tutorial_directory.js index fac078abaab0..4d4cf4566d1f 100644 --- a/src/plugins/home/public/application/components/tutorial_directory.js +++ b/src/plugins/home/public/application/components/tutorial_directory.js @@ -301,7 +301,7 @@ class TutorialDirectoryUi extends React.Component { {this.renderHeader()} {this.renderDataSourceSelector()} - {this.renderTabs()} + {this.renderTabs()} {this.renderTabContent()} diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx index 8c1586b3a916..bca734a1cead 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx @@ -296,6 +296,7 @@ export function Tabs({ indexPattern, saveIndexPattern, fields, history, location setSelectedTabId(tab.id); syncingStateFunc.setCurrentTab(tab.id); }} + size="s" /> ); } diff --git a/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/__snapshots__/help_flyout.test.tsx.snap b/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/__snapshots__/help_flyout.test.tsx.snap index 0531fcf988fb..49bdc51e178c 100644 --- a/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/__snapshots__/help_flyout.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/__snapshots__/help_flyout.test.tsx.snap @@ -16,6 +16,7 @@ exports[`ScriptingHelpFlyout should render normally 1`] = ` "name": "Syntax", } } + size="s" tabs={ Array [ Object { @@ -57,6 +58,7 @@ exports[`ScriptingHelpFlyout should render nothing if not visible 1`] = ` "name": "Syntax", } } + size="s" tabs={ Array [ Object { diff --git a/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/help_flyout.tsx b/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/help_flyout.tsx index d2331f7f8d6f..6e6dc9accd26 100644 --- a/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/help_flyout.tsx +++ b/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/help_flyout.tsx @@ -82,7 +82,7 @@ export const ScriptingHelpFlyout: React.FC = ({ return isVisible ? ( - + ) : null; diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_picker.js b/src/plugins/vis_type_timeseries/public/application/components/vis_picker.js index e2953d4022b7..409f4ba76b1f 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_picker.js +++ b/src/plugins/vis_type_timeseries/public/application/components/vis_picker.js @@ -111,7 +111,7 @@ export const VisPicker = injectI18n(function (props) { ); }); - return {tabs}; + return {tabs}; }); VisPicker.propTypes = { From 49677e90ed34be27b6b720e976384ad5e8b0fb25 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:44:17 -0700 Subject: [PATCH 073/276] [Look&Feel] Update dsahboards/visualziation list title to use standard size (#7226) (#7234) (cherry picked from commit c3dd7687ee6b8a58f38303a550111d08e36e8a6f) Signed-off-by: Zhongnan Su Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../public/table_list_view/table_list_view.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/opensearch_dashboards_react/public/table_list_view/table_list_view.tsx b/src/plugins/opensearch_dashboards_react/public/table_list_view/table_list_view.tsx index 438c577d49d4..e737fb2ec73e 100644 --- a/src/plugins/opensearch_dashboards_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/opensearch_dashboards_react/public/table_list_view/table_list_view.tsx @@ -33,7 +33,6 @@ import { FormattedMessage } from '@osd/i18n/react'; import { i18n } from '@osd/i18n'; import { debounce, keyBy, sortBy, uniq } from 'lodash'; import { - EuiTitle, EuiInMemoryTable, EuiPage, EuiPageBody, @@ -525,9 +524,9 @@ class TableListView extends React.Component - +

{this.props.tableListTitle}

-
+
{this.props.createButton || defaultCreateButton} From bbab1ada0a95c6e54bb240e99a05a26fc8c22819 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 16:47:32 +0800 Subject: [PATCH 074/276] [Workspace] Unassign data source before deleteByWorkspace (#7279) (#7284) * unassign data source before deleteByWorkspace * Changeset file for PR #7279 created/updated --------- (cherry picked from commit d67d6ba1c82153c4a1ea7874ac05f142f41f4eac) Signed-off-by: tygao Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7279.yml | 2 ++ .../workspace/server/workspace_client.test.ts | 16 ++++++++++++++++ src/plugins/workspace/server/workspace_client.ts | 15 +++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 changelogs/fragments/7279.yml diff --git a/changelogs/fragments/7279.yml b/changelogs/fragments/7279.yml new file mode 100644 index 000000000000..794bed4a448d --- /dev/null +++ b/changelogs/fragments/7279.yml @@ -0,0 +1,2 @@ +fix: +- Unassign data source before deleteByWorkspace ([#7279](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7279)) \ No newline at end of file diff --git a/src/plugins/workspace/server/workspace_client.test.ts b/src/plugins/workspace/server/workspace_client.test.ts index 208def26ad02..4339d9380341 100644 --- a/src/plugins/workspace/server/workspace_client.test.ts +++ b/src/plugins/workspace/server/workspace_client.test.ts @@ -180,4 +180,20 @@ describe('#WorkspaceClient', () => { expect(mockCheckAndSetDefaultDataSource).toHaveBeenCalledWith(uiSettingsClient, ['id1'], true); }); + + it('delete# should unassign data source before deleting related saved objects', async () => { + const client = new WorkspaceClient(coreSetup, logger); + await client.setup(coreSetup); + client?.setSavedObjects(savedObjects); + client?.setUiSettings(uiSettings); + + await client.delete(mockRequestDetail, mockWorkspaceId); + + expect(deleteFromWorkspaces).toHaveBeenCalledWith(DATA_SOURCE_SAVED_OBJECT_TYPE, 'id1', [ + mockWorkspaceId, + ]); + expect(deleteFromWorkspaces).toHaveBeenCalledWith(DATA_SOURCE_SAVED_OBJECT_TYPE, 'id2', [ + mockWorkspaceId, + ]); + }); }); diff --git a/src/plugins/workspace/server/workspace_client.ts b/src/plugins/workspace/server/workspace_client.ts index 159136e1304f..fe88436f38e5 100644 --- a/src/plugins/workspace/server/workspace_client.ts +++ b/src/plugins/workspace/server/workspace_client.ts @@ -306,6 +306,21 @@ export class WorkspaceClient implements IWorkspaceClientImpl { }), }; } + + // When workspace is to be deleted, unassign all assigned data source before deleting saved object by workspace. + const selectedDataSources = await getDataSourcesList(savedObjectClient, [id]); + if (selectedDataSources.length > 0) { + const promises = []; + for (const dataSource of selectedDataSources) { + promises.push( + savedObjectClient.deleteFromWorkspaces(DATA_SOURCE_SAVED_OBJECT_TYPE, dataSource.id, [ + id, + ]) + ); + } + await Promise.all(promises); + } + await savedObjectClient.deleteByWorkspace(id); // delete workspace itself at last, deleteByWorkspace depends on the workspace to do permission check await savedObjectClient.delete(WORKSPACE_TYPE, id); From 0e0ea519ce84cb3fc85e9c53cb50def0d49b92e5 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 20:20:31 +0800 Subject: [PATCH 075/276] [Workspace] Support workspace detail page (#7241) (#7302) --- changelogs/fragments/7241.yml | 2 + src/plugins/workspace/common/constants.ts | 5 +- src/plugins/workspace/public/application.tsx | 29 +- .../public/components/utils/workspace.test.ts | 36 +- .../public/components/utils/workspace.ts | 19 +- .../workspace_creator.test.tsx | 2 +- .../workspace_creator/workspace_creator.tsx | 4 +- .../workspace_detail.test.tsx.snap | 154 +++++++++ .../index.tsx | 2 +- .../workspace_detail.test.tsx | 115 +++++++ .../workspace_detail/workspace_detail.tsx | 103 ++++++ .../workspace_detail_content.tsx} | 4 +- .../workspace_updater.test.tsx | 76 ++++- .../workspace_updater.tsx | 20 +- ...rview_app.tsx => workspace_detail_app.tsx} | 6 +- .../components/workspace_form/constants.ts | 23 ++ .../public/components/workspace_form/index.ts | 1 + .../select_data_source_panel.tsx | 14 +- .../public/components/workspace_form/types.ts | 3 +- .../workspace_form/use_workspace_form.test.ts | 2 +- .../workspace_form/workspace_detail_form.scss | 8 + .../workspace_form/workspace_detail_form.tsx | 146 ++++++++ .../workspace_enter_details_panel.tsx | 111 +++++++ .../workspace_form/workspace_form.tsx | 142 ++------ .../workspace_use_case.test.tsx | 3 + .../workspace_form/workspace_use_case.tsx | 48 ++- .../components/workspace_list/index.test.tsx | 6 +- .../components/workspace_list/index.tsx | 15 +- .../workspace_menu/workspace_menu.test.tsx | 2 +- .../workspace_menu/workspace_menu.tsx | 4 +- .../workspace_overview.test.tsx.snap | 314 ------------------ .../all_get_started_cards.ts | 174 ---------- .../getting_start_card.test.tsx | 58 ---- .../workspace_overview/getting_start_card.tsx | 66 ---- .../getting_start_modal.test.tsx | 106 ------ .../getting_start_modal.tsx | 139 -------- .../components/workspace_overview/index.scss | 30 -- .../components/workspace_overview/types.ts | 21 -- .../workspace_overview.test.tsx | 240 ------------- .../workspace_overview/workspace_overview.tsx | 208 ------------ .../workspace_overview_settings.tsx | 20 -- .../components/workspace_updater_app.tsx | 35 -- src/plugins/workspace/public/plugin.test.ts | 14 +- src/plugins/workspace/public/plugin.ts | 36 +- 44 files changed, 855 insertions(+), 1711 deletions(-) create mode 100644 changelogs/fragments/7241.yml create mode 100644 src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap rename src/plugins/workspace/public/components/{workspace_updater => workspace_detail}/index.tsx (51%) create mode 100644 src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx create mode 100644 src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx rename src/plugins/workspace/public/components/{workspace_overview/workspace_overview_content.tsx => workspace_detail/workspace_detail_content.tsx} (88%) rename src/plugins/workspace/public/components/{workspace_updater => workspace_detail}/workspace_updater.test.tsx (84%) rename src/plugins/workspace/public/components/{workspace_updater => workspace_detail}/workspace_updater.tsx (91%) rename src/plugins/workspace/public/components/{workspace_overview_app.tsx => workspace_detail_app.tsx} (83%) create mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss create mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx create mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_overview/__snapshots__/workspace_overview.test.tsx.snap delete mode 100644 src/plugins/workspace/public/components/workspace_overview/all_get_started_cards.ts delete mode 100644 src/plugins/workspace/public/components/workspace_overview/getting_start_card.test.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_overview/getting_start_card.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_overview/getting_start_modal.test.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_overview/getting_start_modal.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_overview/index.scss delete mode 100644 src/plugins/workspace/public/components/workspace_overview/types.ts delete mode 100644 src/plugins/workspace/public/components/workspace_overview/workspace_overview.test.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_overview/workspace_overview.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_overview/workspace_overview_settings.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_updater_app.tsx diff --git a/changelogs/fragments/7241.yml b/changelogs/fragments/7241.yml new file mode 100644 index 000000000000..fc0c3bd7ded7 --- /dev/null +++ b/changelogs/fragments/7241.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace] Support workspace detail page ([#7241](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7241)) \ No newline at end of file diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index a1f9e7d38e40..bdf9aa8ddfc5 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -9,13 +9,12 @@ import { AppCategory } from '../../../core/types'; export const WORKSPACE_FATAL_ERROR_APP_ID = 'workspace_fatal_error'; export const WORKSPACE_CREATE_APP_ID = 'workspace_create'; export const WORKSPACE_LIST_APP_ID = 'workspace_list'; -export const WORKSPACE_UPDATE_APP_ID = 'workspace_update'; -export const WORKSPACE_OVERVIEW_APP_ID = 'workspace_overview'; +export const WORKSPACE_DETAIL_APP_ID = 'workspace_detail'; /** * Since every workspace always have overview and update page, these features will be selected by default * and can't be changed in the workspace form feature selector */ -export const DEFAULT_SELECTED_FEATURES_IDS = [WORKSPACE_UPDATE_APP_ID, WORKSPACE_OVERVIEW_APP_ID]; +export const DEFAULT_SELECTED_FEATURES_IDS = [WORKSPACE_DETAIL_APP_ID]; export const WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID = 'workspace'; export const WORKSPACE_CONFLICT_CONTROL_SAVED_OBJECTS_CLIENT_WRAPPER_ID = 'workspace_conflict_control'; diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index 7ca706a0a161..717c0aadd623 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -9,13 +9,11 @@ import { AppMountParameters, ScopedHistory } from '../../../core/public'; import { OpenSearchDashboardsContextProvider } from '../../opensearch_dashboards_react/public'; import { WorkspaceFatalError } from './components/workspace_fatal_error'; import { WorkspaceCreatorApp } from './components/workspace_creator_app'; -import { WorkspaceUpdaterApp } from './components/workspace_updater_app'; import { WorkspaceListApp } from './components/workspace_list_app'; -import { WorkspaceUpdaterProps } from './components/workspace_updater'; import { Services } from './types'; import { WorkspaceCreatorProps } from './components/workspace_creator/workspace_creator'; -import { WorkspaceOverviewApp } from './components/workspace_overview_app'; -import { WorkspaceOverviewProps } from './components/workspace_overview/workspace_overview'; +import { WorkspaceDetailApp } from './components/workspace_detail_app'; +import { WorkspaceDetailProps } from './components/workspace_detail/workspace_detail'; export const renderCreatorApp = ( { element }: AppMountParameters, @@ -34,23 +32,6 @@ export const renderCreatorApp = ( }; }; -export const renderUpdaterApp = ( - { element }: AppMountParameters, - services: Services, - props: WorkspaceUpdaterProps -) => { - ReactDOM.render( - - - , - element - ); - - return () => { - ReactDOM.unmountComponentAtNode(element); - }; -}; - export const renderFatalErrorApp = (params: AppMountParameters, services: Services) => { const { element } = params; const history = params.history as ScopedHistory<{ error?: string }>; @@ -78,14 +59,14 @@ export const renderListApp = ({ element }: AppMountParameters, services: Service }; }; -export const renderOverviewApp = ( +export const renderDetailApp = ( { element }: AppMountParameters, services: Services, - props: WorkspaceOverviewProps + props: WorkspaceDetailProps ) => { ReactDOM.render( - + , element ); diff --git a/src/plugins/workspace/public/components/utils/workspace.test.ts b/src/plugins/workspace/public/components/utils/workspace.test.ts index 926455feed34..5676b0d1aa99 100644 --- a/src/plugins/workspace/public/components/utils/workspace.test.ts +++ b/src/plugins/workspace/public/components/utils/workspace.test.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { switchWorkspace, navigateToWorkspaceUpdatePage } from './workspace'; +import { navigateToWorkspaceDetail } from './workspace'; import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; jest.mock('../../../../../core/public/utils'); @@ -20,7 +20,7 @@ describe('workspace utils', () => { coreStartMock.application.navigateToUrl = mockNavigateToUrl; }); - describe('switchWorkspace', () => { + describe('navigateToWorkspaceDetail', () => { it('should redirect if newUrl is returned', () => { Object.defineProperty(window, 'location', { value: { @@ -30,35 +30,7 @@ describe('workspace utils', () => { }); // @ts-ignore formatUrlWithWorkspaceId.mockImplementation(() => 'new_url'); - switchWorkspace({ application: coreStartMock.application, http: coreStartMock.http }, ''); - expect(mockNavigateToUrl).toHaveBeenCalledWith('new_url'); - }); - - it('should not redirect if newUrl is not returned', () => { - Object.defineProperty(window, 'location', { - value: { - href: defaultUrl, - }, - writable: true, - }); - // @ts-ignore - formatUrlWithWorkspaceId.mockImplementation(() => ''); - switchWorkspace({ application: coreStartMock.application, http: coreStartMock.http }, ''); - expect(mockNavigateToUrl).not.toBeCalled(); - }); - }); - - describe('navigateToWorkspaceUpdatePage', () => { - it('should redirect if newUrl is returned', () => { - Object.defineProperty(window, 'location', { - value: { - href: defaultUrl, - }, - writable: true, - }); - // @ts-ignore - formatUrlWithWorkspaceId.mockImplementation(() => 'new_url'); - navigateToWorkspaceUpdatePage( + navigateToWorkspaceDetail( { application: coreStartMock.application, http: coreStartMock.http }, '' ); @@ -74,7 +46,7 @@ describe('workspace utils', () => { }); // @ts-ignore formatUrlWithWorkspaceId.mockImplementation(() => ''); - navigateToWorkspaceUpdatePage( + navigateToWorkspaceDetail( { application: coreStartMock.application, http: coreStartMock.http }, '' ); diff --git a/src/plugins/workspace/public/components/utils/workspace.ts b/src/plugins/workspace/public/components/utils/workspace.ts index 63ed5953dbfa..c7ba243bdf91 100644 --- a/src/plugins/workspace/public/components/utils/workspace.ts +++ b/src/plugins/workspace/public/components/utils/workspace.ts @@ -3,28 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { WORKSPACE_OVERVIEW_APP_ID, WORKSPACE_UPDATE_APP_ID } from '../../../common/constants'; +import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants'; import { CoreStart } from '../../../../../core/public'; import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; type Core = Pick; -export const switchWorkspace = ({ application, http }: Core, id: string) => { +export const navigateToWorkspaceDetail = ({ application, http }: Core, id: string) => { const newUrl = formatUrlWithWorkspaceId( - application.getUrlForApp(WORKSPACE_OVERVIEW_APP_ID, { - absolute: true, - }), - id, - http.basePath - ); - if (newUrl) { - application.navigateToUrl(newUrl); - } -}; - -export const navigateToWorkspaceUpdatePage = ({ application, http }: Core, id: string) => { - const newUrl = formatUrlWithWorkspaceId( - application.getUrlForApp(WORKSPACE_UPDATE_APP_ID, { + application.getUrlForApp(WORKSPACE_DETAIL_APP_ID, { absolute: true, }), id, diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx index 3e7d48a8faf3..ad3b79da4788 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx @@ -59,7 +59,7 @@ const WorkspaceCreator = (props: any, isDashboardAdmin = false) => { }, }, navigateToApp, - getUrlForApp: jest.fn(() => '/app/workspace_overview'), + getUrlForApp: jest.fn(() => '/app/workspace_detail'), applications$: new BehaviorSubject>(PublicAPPInfoMap as any), }, notifications: { diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx index e06155c32c4e..9d4ccaaef1cb 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx @@ -12,7 +12,7 @@ import { BehaviorSubject, of } from 'rxjs'; import { PublicAppInfo } from 'opensearch-dashboards/public'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { WorkspaceForm, WorkspaceFormSubmitData, WorkspaceOperationType } from '../workspace_form'; -import { WORKSPACE_OVERVIEW_APP_ID } from '../../../common/constants'; +import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants'; import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; import { WorkspaceClient } from '../../workspace_client'; import { convertPermissionSettingsToPermissions } from '../workspace_form'; @@ -65,7 +65,7 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { // Redirect page after one second, leave one second time to show create successful toast. window.setTimeout(() => { window.location.href = formatUrlWithWorkspaceId( - application.getUrlForApp(WORKSPACE_OVERVIEW_APP_ID, { + application.getUrlForApp(WORKSPACE_DETAIL_APP_ID, { absolute: true, }), newWorkspaceId, diff --git a/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap b/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap new file mode 100644 index 000000000000..24a70b2a0352 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap @@ -0,0 +1,154 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`WorkspaceDetail render workspace detail page normally 1`] = ` +
+
+
+
+
+
+

+
+
+ foo +
+
+

+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+ + About + +
+

+ this is my foo workspace description +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/src/plugins/workspace/public/components/workspace_updater/index.tsx b/src/plugins/workspace/public/components/workspace_detail/index.tsx similarity index 51% rename from src/plugins/workspace/public/components/workspace_updater/index.tsx rename to src/plugins/workspace/public/components/workspace_detail/index.tsx index b00065a00f64..c4a94b2a6899 100644 --- a/src/plugins/workspace/public/components/workspace_updater/index.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/index.tsx @@ -3,4 +3,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -export { WorkspaceUpdater, WorkspaceUpdaterProps } from './workspace_updater'; +export { WorkspaceDetail } from './workspace_detail'; diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx new file mode 100644 index 000000000000..8b2937abd6c2 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx @@ -0,0 +1,115 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import React from 'react'; +import { coreMock } from '../../../../../core/public/mocks'; +import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; +import { BehaviorSubject } from 'rxjs'; +import { PublicAppInfo, WorkspaceObject } from 'opensearch-dashboards/public'; +import { WorkspaceDetail } from './workspace_detail'; + +// all applications +const PublicAPPInfoMap = new Map([ + ['alerting', { id: 'alerting', title: 'alerting' }], + ['home', { id: 'home', title: 'home' }], +]); + +const mockCoreStart = coreMock.createStart(); + +const workspaceObject = { + id: 'foo_id', + name: 'foo', + description: 'this is my foo workspace description', + features: ['use-case-observability'], + color: '', + icon: '', + reserved: false, +}; + +const createWorkspacesSetupContractMockWithValue = (workspace?: WorkspaceObject) => { + const currentWorkspace = workspace ? workspace : workspaceObject; + const currentWorkspaceId$ = new BehaviorSubject(currentWorkspace.id); + const workspaceList$ = new BehaviorSubject([currentWorkspace]); + const currentWorkspace$ = new BehaviorSubject(currentWorkspace); + const initialized$ = new BehaviorSubject(true); + return { + currentWorkspaceId$, + workspaceList$, + currentWorkspace$, + initialized$, + }; +}; + +const WorkspaceDetailPage = (props: any) => { + const workspacesService = props.workspacesService || createWorkspacesSetupContractMockWithValue(); + const { Provider } = createOpenSearchDashboardsReactContext({ + ...mockCoreStart, + ...{ + application: { + ...mockCoreStart.application, + applications$: new BehaviorSubject>(PublicAPPInfoMap as any), + capabilities: { + ...mockCoreStart.application.capabilities, + workspaces: { + permissionEnabled: true, + }, + }, + }, + workspaces: workspacesService, + savedObjects: { + ...mockCoreStart.savedObjects, + client: { + ...mockCoreStart.savedObjects.client, + find: jest.fn().mockResolvedValue({ + savedObjects: [], + }), + }, + }, + }, + }); + + return ( + + + + ); +}; + +describe('WorkspaceDetail', () => { + it('render workspace detail page normally', async () => { + const { container } = render(WorkspaceDetailPage({})); + expect(container).toMatchSnapshot(); + }); + + it('default selected tab is overview', async () => { + const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); + render(WorkspaceDetailPage({ workspacesService: workspaceService })); + expect(screen.queryByText('foo')).not.toBeNull(); + expect(document.querySelector('#overview')).toHaveClass('euiTab-isSelected'); + }); + + it('click on collaborators tab will workspace update page with permission', async () => { + const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); + const { getByText } = render(WorkspaceDetailPage({ workspacesService: workspaceService })); + await act(async () => { + fireEvent.click(getByText('Collaborators')); + }); + expect(document.querySelector('#collaborators')).toHaveClass('euiTab-isSelected'); + await waitFor(() => { + expect(screen.queryByText('Manage access and permissions')).not.toBeNull(); + }); + }); + + it('click on settings tab will show workspace update page', async () => { + const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); + const { getByText } = render(WorkspaceDetailPage({ workspacesService: workspaceService })); + fireEvent.click(getByText('Settings')); + expect(document.querySelector('#settings')).toHaveClass('euiTab-isSelected'); + await waitFor(() => { + expect(screen.queryByText('Enter details')).not.toBeNull(); + }); + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx new file mode 100644 index 000000000000..efa5e5a68194 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx @@ -0,0 +1,103 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { + EuiPage, + EuiPageBody, + EuiPageHeader, + EuiFlexItem, + EuiTabbedContent, + EuiFlexGroup, + EuiPanel, +} from '@elastic/eui'; + +import { useObservable } from 'react-use'; +import { i18n } from '@osd/i18n'; +import { CoreStart, PublicAppInfo } from 'opensearch-dashboards/public'; +import { BehaviorSubject } from 'rxjs'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { WorkspaceDetailContent } from './workspace_detail_content'; +import { WorkspaceUpdater } from './workspace_updater'; +import { DetailTab } from '../workspace_form/constants'; + +export interface WorkspaceDetailProps { + workspaceConfigurableApps$?: BehaviorSubject; +} + +export const WorkspaceDetail = (props: WorkspaceDetailProps) => { + const { + services: { workspaces, application }, + } = useOpenSearchDashboards(); + + const currentWorkspace = useObservable(workspaces.currentWorkspace$); + const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; + + if (!currentWorkspace) { + return null; + } + + const pageTitle = ( + + {currentWorkspace?.name} + + ); + + const detailTabs = [ + { + id: DetailTab.Overview, + name: i18n.translate('workspace.overview.tabTitle', { + defaultMessage: 'Overview', + }), + content: , + }, + { + id: DetailTab.Settings, + name: i18n.translate('workspace.overview.setting.tabTitle', { + defaultMessage: 'Settings', + }), + content: ( + + ), + }, + ...(isPermissionEnabled + ? [ + { + id: DetailTab.Collaborators, + name: i18n.translate('workspace.overview.collaborators.tabTitle', { + defaultMessage: 'Collaborators', + }), + content: ( + + ), + }, + ] + : []), + ]; + + return ( + <> + + + + + + + + + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_overview/workspace_overview_content.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_content.tsx similarity index 88% rename from src/plugins/workspace/public/components/workspace_overview/workspace_overview_content.tsx rename to src/plugins/workspace/public/components/workspace_detail/workspace_detail_content.tsx index 6b2ad0fbe689..3e3010e4143d 100644 --- a/src/plugins/workspace/public/components/workspace_overview/workspace_overview_content.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_content.tsx @@ -15,9 +15,9 @@ import { import React from 'react'; import { useObservable } from 'react-use'; import { of } from 'rxjs'; -import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -export const WorkspaceOverviewContent = () => { +export const WorkspaceDetailContent = () => { const { services: { workspaces }, } = useOpenSearchDashboards(); diff --git a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx similarity index 84% rename from src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx rename to src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx index 96de2c6c7947..707f72e17ce6 100644 --- a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.test.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx @@ -10,6 +10,7 @@ import { BehaviorSubject } from 'rxjs'; import { WorkspaceUpdater as WorkspaceUpdaterComponent } from './workspace_updater'; import { coreMock, workspacesServiceMock } from '../../../../../core/public/mocks'; import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; +import { DetailTab } from '../workspace_form/constants'; const workspaceClientUpdate = jest.fn().mockReturnValue({ result: true, success: true }); @@ -21,9 +22,9 @@ const PublicAPPInfoMap = new Map([ ['dashboards', { id: 'dashboards', title: 'Dashboards' }], ]); const createWorkspacesSetupContractMockWithValue = () => { - const currentWorkspaceId$ = new BehaviorSubject('abljlsds'); + const currentWorkspaceId$ = new BehaviorSubject('workspaceId'); const currentWorkspace = { - id: 'abljlsds', + id: 'workspaceId', name: 'test1', description: 'test1', features: ['use-case-observability'], @@ -86,7 +87,7 @@ const WorkspaceUpdater = (props: any) => { }, }, navigateToApp, - getUrlForApp: jest.fn(() => '/app/workspace_overview'), + getUrlForApp: jest.fn(() => '/app/workspace_detail'), applications$: new BehaviorSubject>(PublicAPPInfoMap as any), }, workspaces: workspacesService, @@ -155,6 +156,7 @@ describe('WorkspaceUpdater', () => { ); expect(container).toMatchInlineSnapshot(`
`); @@ -164,6 +166,7 @@ describe('WorkspaceUpdater', () => { const { getByTestId } = render( ); @@ -180,6 +183,7 @@ describe('WorkspaceUpdater', () => { const { findByText, getByTestId } = render( ); await waitFor(renderCompleted); @@ -190,10 +194,11 @@ describe('WorkspaceUpdater', () => { expect(navigateToApp).toHaveBeenCalled(); }); - it('update workspace successfully', async () => { - const { getByTestId, getAllByTestId, getAllByLabelText } = render( + it('update workspace successfully without permission', async () => { + const { getByTestId, getAllByLabelText } = render( ); await waitFor(renderCompleted); @@ -217,6 +222,49 @@ describe('WorkspaceUpdater', () => { fireEvent.click(getByTestId('workspaceUseCase-observability')); fireEvent.click(getByTestId('workspaceUseCase-analytics')); + act(() => { + fireEvent.click(getAllByLabelText('Delete data source')[0]); + }); + + fireEvent.click(getByTestId('workspaceForm-bottomBar-updateButton')); + expect(workspaceClientUpdate).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + name: 'test workspace name', + color: '#000000', + description: 'test workspace description', + features: expect.arrayContaining(['use-case-analytics']), + }), + { + permissions: { + library_write: { + users: ['foo'], + }, + write: { + users: ['foo'], + }, + }, + dataSources: ['id2'], + } + ); + await waitFor(() => { + expect(notificationToastsAddSuccess).toHaveBeenCalled(); + }); + expect(notificationToastsAddDanger).not.toHaveBeenCalled(); + await waitFor(() => { + expect(setHrefSpy).toHaveBeenCalledWith(expect.stringMatching(/workspace_detail$/)); + }); + }); + + it('update workspace permission successfully', async () => { + const { getByTestId, getAllByTestId } = render( + + ); + await waitFor(() => expect(screen.queryByText('Manage access and permissions')).not.toBeNull()); + const userIdInput = getAllByTestId('comboBoxSearchInput')[0]; fireEvent.click(userIdInput); @@ -225,18 +273,13 @@ describe('WorkspaceUpdater', () => { }); fireEvent.blur(userIdInput); - await act(() => { - fireEvent.click(getAllByLabelText('Delete data source')[0]); - }); - fireEvent.click(getByTestId('workspaceForm-bottomBar-updateButton')); expect(workspaceClientUpdate).toHaveBeenCalledWith( expect.any(String), expect.objectContaining({ - name: 'test workspace name', - color: '#000000', - description: 'test workspace description', - features: expect.arrayContaining(['use-case-analytics']), + name: 'test1', + description: 'test1', + features: expect.arrayContaining(['use-case-observability']), }), { permissions: { @@ -247,7 +290,7 @@ describe('WorkspaceUpdater', () => { users: ['test user id'], }, }, - dataSources: ['id2'], + dataSources: ['id1', 'id2'], } ); await waitFor(() => { @@ -255,7 +298,7 @@ describe('WorkspaceUpdater', () => { }); expect(notificationToastsAddDanger).not.toHaveBeenCalled(); await waitFor(() => { - expect(setHrefSpy).toHaveBeenCalledWith(expect.stringMatching(/workspace_overview$/)); + expect(setHrefSpy).toHaveBeenCalledWith(expect.stringMatching(/workspace_detail$/)); }); }); @@ -264,6 +307,7 @@ describe('WorkspaceUpdater', () => { const { getByTestId } = render( ); await waitFor(renderCompleted); @@ -287,6 +331,7 @@ describe('WorkspaceUpdater', () => { const { getByTestId } = render( ); await waitFor(renderCompleted); @@ -309,6 +354,7 @@ describe('WorkspaceUpdater', () => { ); diff --git a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx similarity index 91% rename from src/plugins/workspace/public/components/workspace_updater/workspace_updater.tsx rename to src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx index a27ef6e88a45..f0c4869f441f 100644 --- a/src/plugins/workspace/public/components/workspace_updater/workspace_updater.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx @@ -4,31 +4,31 @@ */ import React, { useCallback, useEffect, useState } from 'react'; -import { EuiPage, EuiPageBody, EuiPageHeader, EuiPageContent } from '@elastic/eui'; +import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { PublicAppInfo } from 'opensearch-dashboards/public'; import { useObservable } from 'react-use'; import { BehaviorSubject, of } from 'rxjs'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { WORKSPACE_OVERVIEW_APP_ID } from '../../../common/constants'; +import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants'; import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; import { WorkspaceAttributeWithPermission } from '../../../../../core/types'; import { WorkspaceClient } from '../../workspace_client'; import { - WorkspaceForm, WorkspaceFormSubmitData, WorkspaceOperationType, convertPermissionsToPermissionSettings, convertPermissionSettingsToPermissions, + WorkspaceDetailForm, } from '../workspace_form'; import { getDataSourcesList } from '../../utils'; import { DataSource } from '../../../common/types'; +import { DetailTab } from '../workspace_form/constants'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; export interface WorkspaceUpdaterProps { workspaceConfigurableApps$?: BehaviorSubject; - hideTitle?: boolean; - maxWidth?: number | string; + detailTab?: DetailTab; } function getFormDataFromWorkspace( @@ -64,7 +64,6 @@ export const WorkspaceUpdater = (props: WorkspaceUpdaterProps) => { workspaceClient: WorkspaceClient; dataSourceManagement?: DataSourceManagementPluginSetup; }>(); - const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; const currentWorkspace = useObservable(workspaces ? workspaces.currentWorkspace$ : of(null)); const workspaceConfigurableApps = useObservable( @@ -103,7 +102,7 @@ export const WorkspaceUpdater = (props: WorkspaceUpdaterProps) => { // Redirect page after one second, leave one second time to show update successful toast. window.setTimeout(() => { window.location.href = formatUrlWithWorkspaceId( - application.getUrlForApp(WORKSPACE_OVERVIEW_APP_ID, { + application.getUrlForApp(WORKSPACE_DETAIL_APP_ID, { absolute: true, }), currentWorkspace.id, @@ -148,23 +147,24 @@ export const WorkspaceUpdater = (props: WorkspaceUpdaterProps) => { return ( - {!props.hideTitle ? : null} + {application && savedObjects && ( - )} diff --git a/src/plugins/workspace/public/components/workspace_overview_app.tsx b/src/plugins/workspace/public/components/workspace_detail_app.tsx similarity index 83% rename from src/plugins/workspace/public/components/workspace_overview_app.tsx rename to src/plugins/workspace/public/components/workspace_detail_app.tsx index c581aad9d322..2236cd67c139 100644 --- a/src/plugins/workspace/public/components/workspace_overview_app.tsx +++ b/src/plugins/workspace/public/components/workspace_detail_app.tsx @@ -9,9 +9,9 @@ import { CoreStart } from 'opensearch-dashboards/public'; import { useObservable } from 'react-use'; import { EuiBreadcrumb } from '@elastic/eui'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; -import { WorkspaceOverview, WorkspaceOverviewProps } from './workspace_overview/workspace_overview'; +import { WorkspaceDetail, WorkspaceDetailProps } from './workspace_detail/workspace_detail'; -export const WorkspaceOverviewApp = (props: WorkspaceOverviewProps) => { +export const WorkspaceDetailApp = (props: WorkspaceDetailProps) => { const { services: { workspaces, chrome, application }, } = useOpenSearchDashboards(); @@ -40,7 +40,7 @@ export const WorkspaceOverviewApp = (props: WorkspaceOverviewProps) => { return ( - + ); }; diff --git a/src/plugins/workspace/public/components/workspace_form/constants.ts b/src/plugins/workspace/public/components/workspace_form/constants.ts index 1f4e4260a343..2a2c7142d6f0 100644 --- a/src/plugins/workspace/public/components/workspace_form/constants.ts +++ b/src/plugins/workspace/public/components/workspace_form/constants.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { i18n } from '@osd/i18n'; import { WorkspacePermissionMode } from '../../../common/constants'; export enum WorkspaceOperationType { @@ -31,3 +32,25 @@ export const optionIdToWorkspacePermissionModesMap: { ], [PermissionModeId.Owner]: [WorkspacePermissionMode.LibraryWrite, WorkspacePermissionMode.Write], }; + +export const workspaceDetailsTitle = i18n.translate('workspace.form.workspaceDetails.title', { + defaultMessage: 'Enter details', +}); + +export const workspaceUseCaseTitle = i18n.translate('workspace.form.workspaceUseCase.title', { + defaultMessage: 'Choose one or more focus areas', +}); + +export const selectDataSourceTitle = i18n.translate('workspace.form.selectDataSource.title', { + defaultMessage: 'Associate data source', +}); + +export const usersAndPermissionsTitle = i18n.translate('workspace.form.usersAndPermissions.title', { + defaultMessage: 'Manage access and permissions', +}); + +export enum DetailTab { + Settings = 'settings', + Collaborators = 'collaborators', + Overview = 'overview', +} diff --git a/src/plugins/workspace/public/components/workspace_form/index.ts b/src/plugins/workspace/public/components/workspace_form/index.ts index 416592ff2006..31addf5a641e 100644 --- a/src/plugins/workspace/public/components/workspace_form/index.ts +++ b/src/plugins/workspace/public/components/workspace_form/index.ts @@ -4,6 +4,7 @@ */ export { WorkspaceForm } from './workspace_form'; +export { WorkspaceDetailForm } from './workspace_detail_form'; export { WorkspaceFormSubmitData } from './types'; export { WorkspaceOperationType } from './constants'; export { diff --git a/src/plugins/workspace/public/components/workspace_form/select_data_source_panel.tsx b/src/plugins/workspace/public/components/workspace_form/select_data_source_panel.tsx index 472a98a460d4..e7bc280882c1 100644 --- a/src/plugins/workspace/public/components/workspace_form/select_data_source_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_form/select_data_source_panel.tsx @@ -7,13 +7,13 @@ import React, { useCallback, useEffect, useState } from 'react'; import { EuiButton, EuiFormRow, - EuiText, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiButtonIcon, EuiComboBox, EuiComboBoxOptionOption, + EuiFormLabel, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { SavedObjectsStart } from '../../../../../core/public'; @@ -88,13 +88,11 @@ export const SelectDataSourcePanel = ({ return (
- - - {i18n.translate('workspace.form.selectDataSource.subTitle', { - defaultMessage: 'Data source', - })} - - + + {i18n.translate('workspace.form.selectDataSource.subTitle', { + defaultMessage: 'Data source', + })} + {selectedDataSources.map(({ id, title }, index) => ( { expect(onSubmitMock).toHaveBeenCalledWith( expect.objectContaining({ name: 'test-workspace-name', - features: ['use-case-observability', 'workspace_update', 'workspace_overview'], + features: ['use-case-observability', 'workspace_detail'], }) ); }); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss new file mode 100644 index 000000000000..12d655151605 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.scss @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +.workspace-detail-form-group { + width: 15%; +} diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx new file mode 100644 index 000000000000..1369abca517e --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx @@ -0,0 +1,146 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import './workspace_detail_form.scss'; +import React, { useRef } from 'react'; +import { EuiPanel, EuiSpacer, EuiForm, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; + +import { WorkspaceBottomBar } from './workspace_bottom_bar'; +import { WorkspaceFormProps } from './types'; +import { useWorkspaceForm } from './use_workspace_form'; +import { WorkspaceUseCase } from './workspace_use_case'; +import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; +import { SelectDataSourcePanel } from './select_data_source_panel'; +import { EnterDetailsPanel } from './workspace_enter_details_panel'; +import { + DetailTab, + WorkspaceOperationType, + selectDataSourceTitle, + usersAndPermissionsTitle, + workspaceDetailsTitle, + workspaceUseCaseTitle, +} from './constants'; +import { WorkspaceCreateActionPanel } from './workspace_create_action_panel'; +import { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; + +interface FormGroupProps { + title: string; + children: React.ReactNode; +} + +const FormGroup = ({ title, children }: FormGroupProps) => ( + + + +

{title}

+
+
+ {children} +
+); + +export const WorkspaceDetailForm = (props: WorkspaceFormProps) => { + const { + detailTab, + application, + savedObjects, + defaultValues, + operationType, + workspaceConfigurableApps, + dataSourceManagement: isDataSourceEnabled, + } = props; + const { + formId, + formData, + formErrors, + numberOfErrors, + numberOfChanges, + handleFormSubmit, + handleColorChange, + handleUseCasesChange, + setPermissionSettings, + handleNameInputChange, + setSelectedDataSources, + handleDescriptionChange, + } = useWorkspaceForm(props); + + const isDashboardAdmin = application?.capabilities?.dashboards?.isDashboardAdmin ?? false; + + const disabledUserOrGroupInputIdsRef = useRef( + defaultValues?.permissionSettings?.map((item) => item.id) ?? [] + ); + + return ( + + {numberOfErrors > 0 && ( + <> + + + + )} + + {detailTab === DetailTab.Collaborators && ( + + + + )} + {detailTab === DetailTab.Settings && ( + <> + + + + + + + + + {isDashboardAdmin && isDataSourceEnabled && ( + + + + )} + + )} + + + {operationType === WorkspaceOperationType.Create && ( + + )} + {operationType === WorkspaceOperationType.Update && ( + + )} + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx new file mode 100644 index 000000000000..649890151204 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx @@ -0,0 +1,111 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiColorPicker, + EuiFieldText, + EuiFormRow, + EuiSpacer, + EuiText, + EuiTextArea, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import React from 'react'; +import { EuiColorPickerOutput } from '@elastic/eui/src/components/color_picker/color_picker'; +import { WorkspaceFormErrors } from './types'; + +export interface EnterDetailsPanelProps { + formErrors: WorkspaceFormErrors; + name?: string; + description?: string; + color?: string; + readOnly: boolean; + handleNameInputChange: React.ChangeEventHandler; + handleDescriptionChange: React.ChangeEventHandler; + handleColorChange: (text: string, output: EuiColorPickerOutput) => void; +} + +export const EnterDetailsPanel = ({ + formErrors, + name, + description, + color, + readOnly, + handleNameInputChange, + handleDescriptionChange, + handleColorChange, +}: EnterDetailsPanelProps) => { + return ( + <> + + + + + Description - optional + + } + > + <> + + {i18n.translate('workspace.form.workspaceDetails.description.introduction', { + defaultMessage: + 'Help others understand the purpose of this workspace by providing an overview of the workspace you’re creating.', + })} + + + + + +
+ + {i18n.translate('workspace.form.workspaceDetails.color.helpText', { + defaultMessage: 'Accent color for your workspace', + })} + + + +
+
+ + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index 35318160c6f6..25381fd94e6c 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -4,18 +4,7 @@ */ import React, { useRef } from 'react'; -import { - EuiPanel, - EuiSpacer, - EuiTitle, - EuiForm, - EuiFormRow, - EuiFieldText, - EuiText, - EuiTextArea, - EuiColorPicker, -} from '@elastic/eui'; -import { i18n } from '@osd/i18n'; +import { EuiPanel, EuiSpacer, EuiTitle, EuiForm } from '@elastic/eui'; import { WorkspaceBottomBar } from './workspace_bottom_bar'; import { WorkspaceFormProps } from './types'; @@ -26,6 +15,13 @@ import { WorkspaceOperationType } from './constants'; import { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; import { WorkspaceCreateActionPanel } from './workspace_create_action_panel'; import { SelectDataSourcePanel } from './select_data_source_panel'; +import { EnterDetailsPanel } from './workspace_enter_details_panel'; +import { + selectDataSourceTitle, + usersAndPermissionsTitle, + workspaceDetailsTitle, + workspaceUseCaseTitle, +} from './constants'; export const WorkspaceForm = (props: WorkspaceFormProps) => { const { @@ -51,9 +47,7 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { setSelectedDataSources, handleDescriptionChange, } = useWorkspaceForm(props); - const workspaceDetailsTitle = i18n.translate('workspace.form.workspaceDetails.title', { - defaultMessage: 'Enter details', - }); + const disabledUserOrGroupInputIdsRef = useRef( defaultValues?.permissionSettings?.map((item) => item.id) ?? [] ); @@ -73,111 +67,35 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => {

{workspaceDetailsTitle}

- - - - - Description - optional - - } - > - <> - - {i18n.translate('workspace.form.workspaceDetails.description.introduction', { - defaultMessage: - 'Help others understand the purpose of this workspace by providing an overview of the workspace you’re creating.', - })} - - - - - -
- - {i18n.translate('workspace.form.workspaceDetails.color.helpText', { - defaultMessage: 'Accent color for your workspace', - })} - - - -
-
+ -

- {i18n.translate('workspace.form.workspaceUseCase.title', { - defaultMessage: 'Choose one or more focus areas', - })} -

+

{workspaceUseCaseTitle}

- - - +
{permissionEnabled && ( -

- {i18n.translate('workspace.form.usersAndPermissions.title', { - defaultMessage: 'Manage access and permissions', - })} -

+

{usersAndPermissionsTitle}

{ {isDashboardAdmin && isDataSourceEnabled && ( -

- {i18n.translate('workspace.form.selectDataSource.title', { - defaultMessage: 'Associate data source', - })} -

+

{selectDataSourceTitle}

) => { const onChangeMock = jest.fn(); + const formErrors: WorkspaceFormErrors = {}; const renderResult = render( ) => { ]} value={[]} onChange={onChangeMock} + formErrors={formErrors} {...options} /> ); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx index 8e47d9eafc77..4cdac4422bf6 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx @@ -5,10 +5,11 @@ import React, { useMemo, useCallback } from 'react'; import { PublicAppInfo } from 'opensearch-dashboards/public'; -import { EuiCheckableCard, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; - +import { EuiCheckableCard, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiText } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; import { WORKSPACE_USE_CASES } from '../../../common/constants'; import './workspace_use_case.scss'; +import { WorkspaceFormErrors } from './types'; const ALL_USE_CASES = [ WORKSPACE_USE_CASES.observability, @@ -57,9 +58,15 @@ export interface WorkspaceUseCaseProps { configurableApps?: PublicAppInfo[]; value: string[]; onChange: (newValue: string[]) => void; + formErrors: WorkspaceFormErrors; } -export const WorkspaceUseCase = ({ configurableApps, value, onChange }: WorkspaceUseCaseProps) => { +export const WorkspaceUseCase = ({ + configurableApps, + value, + onChange, + formErrors, +}: WorkspaceUseCaseProps) => { const availableUseCases = useMemo(() => { if (!configurableApps) { return []; @@ -82,18 +89,27 @@ export const WorkspaceUseCase = ({ configurableApps, value, onChange }: Workspac ); return ( - - {availableUseCases.map(({ id, title, description }) => ( - - - - ))} - + + + {availableUseCases.map(({ id, title, description }) => ( + + + + ))} + + ); }; diff --git a/src/plugins/workspace/public/components/workspace_list/index.test.tsx b/src/plugins/workspace/public/components/workspace_list/index.test.tsx index 6cbf36e0c31e..c716c745736a 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.test.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.test.tsx @@ -8,7 +8,7 @@ import { WorkspaceList } from './index'; import { coreMock } from '../../../../../core/public/mocks'; import { render, fireEvent, screen } from '@testing-library/react'; import { I18nProvider } from '@osd/i18n/react'; -import { switchWorkspace, navigateToWorkspaceUpdatePage } from '../utils/workspace'; +import { navigateToWorkspaceDetail } from '../utils/workspace'; import { of } from 'rxjs'; @@ -87,14 +87,14 @@ describe('WorkspaceList', () => { const { getByText } = render(getWrapWorkspaceListInContext()); const nameLink = getByText('name1'); fireEvent.click(nameLink); - expect(switchWorkspace).toBeCalled(); + expect(navigateToWorkspaceDetail).toBeCalled(); }); it('should be able to update workspace after clicking name', async () => { const { getAllByTestId } = render(getWrapWorkspaceListInContext()); const editIcon = getAllByTestId('workspace-list-edit-icon')[0]; fireEvent.click(editIcon); - expect(navigateToWorkspaceUpdatePage).toBeCalled(); + expect(navigateToWorkspaceDetail).toBeCalled(); }); it('should be able to call delete modal after clicking delete button', async () => { diff --git a/src/plugins/workspace/public/components/workspace_list/index.tsx b/src/plugins/workspace/public/components/workspace_list/index.tsx index 34027b87de5b..563a90f04970 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.tsx @@ -20,7 +20,7 @@ import { i18n } from '@osd/i18n'; import { debounce } from '../../../../../core/public'; import { WorkspaceAttribute } from '../../../../../core/public'; import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public'; -import { switchWorkspace, navigateToWorkspaceUpdatePage } from '../utils/workspace'; +import { navigateToWorkspaceDetail } from '../utils/workspace'; import { WORKSPACE_CREATE_APP_ID, WORKSPACE_USE_CASES } from '../../../common/constants'; @@ -52,16 +52,7 @@ export const WorkspaceList = () => { const handleSwitchWorkspace = useCallback( (id: string) => { if (application && http) { - switchWorkspace({ application, http }, id); - } - }, - [application, http] - ); - - const handleUpdateWorkspace = useCallback( - (id: string) => { - if (application && http) { - navigateToWorkspaceUpdatePage({ application, http }, id); + navigateToWorkspaceDetail({ application, http }, id); } }, [application, http] @@ -130,7 +121,7 @@ export const WorkspaceList = () => { icon: 'pencil', type: 'icon', description: 'Edit workspace', - onClick: ({ id }: WorkspaceAttribute) => handleUpdateWorkspace(id), + onClick: ({ id }: WorkspaceAttribute) => handleSwitchWorkspace(id), 'data-test-subj': 'workspace-list-edit-icon', }, { diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx index c63b232bb232..85ee89482724 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx @@ -74,7 +74,7 @@ describe('', () => { fireEvent.click(screen.getByText(/workspace 1/i)); expect(window.location.assign).toHaveBeenCalledWith( - 'https://test.com/w/workspace-1/app/workspace_overview' + 'https://test.com/w/workspace-1/app/workspace_detail' ); Object.defineProperty(window, 'location', { diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx index 5b16b9766b22..986711a8b3d6 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx @@ -22,7 +22,7 @@ import type { EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; import { WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID, - WORKSPACE_OVERVIEW_APP_ID, + WORKSPACE_DETAIL_APP_ID, } from '../../../common/constants'; import { cleanWorkspaceId, formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; import { CoreStart, WorkspaceObject } from '../../../../../core/public'; @@ -69,7 +69,7 @@ export const WorkspaceMenu = ({ coreStart }: Props) => { const workspaceToItem = (workspace: WorkspaceObject) => { const workspaceURL = formatUrlWithWorkspaceId( - coreStart.application.getUrlForApp(WORKSPACE_OVERVIEW_APP_ID, { + coreStart.application.getUrlForApp(WORKSPACE_DETAIL_APP_ID, { absolute: false, }), workspace.id, diff --git a/src/plugins/workspace/public/components/workspace_overview/__snapshots__/workspace_overview.test.tsx.snap b/src/plugins/workspace/public/components/workspace_overview/__snapshots__/workspace_overview.test.tsx.snap deleted file mode 100644 index 650f0775b8e4..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/__snapshots__/workspace_overview.test.tsx.snap +++ /dev/null @@ -1,314 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`WorkspaceOverview render workspace overview page normally 1`] = ` -
-
-
-
-
-
-

-
-
- foo -
-
-

-
-
-
-
-

- Start working -

-
-
-
-
-
- - - - -
- -
-
-
-
-
- - - - -
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- - - -
-
-
-
-
-
-
-
-
-
- - About - -
-

- this is my foo workspace description -

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`; diff --git a/src/plugins/workspace/public/components/workspace_overview/all_get_started_cards.ts b/src/plugins/workspace/public/components/workspace_overview/all_get_started_cards.ts deleted file mode 100644 index ad7dcad86bb8..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/all_get_started_cards.ts +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { GetStartCard } from './types'; -import { WORKSPACE_APP_CATEGORIES } from '../../../common/constants'; - -/** - * All getting start cards - */ -export const getStartCards: GetStartCard[] = [ - // getStarted - { - id: '', // set id as empty so that it will always show up - featureDescription: 'Discover pre-loaded datasets before adding your own.', - featureName: 'Sample Datasets', - link: '/app/import_sample_data', - category: WORKSPACE_APP_CATEGORIES.getStarted, - }, - { - id: 'workspace_create', - featureDescription: 'Build a collaborative hub for your team.', - featureName: 'Workspaces', - link: '/app/workspace_create', - category: WORKSPACE_APP_CATEGORIES.getStarted, - }, - { - id: 'datasources', - featureDescription: 'Seamlessly integrate your data sources.', - featureName: 'Data Sources', - link: '/app/datasources', - category: WORKSPACE_APP_CATEGORIES.getStarted, - }, - { - id: 'management', - featureDescription: 'Unlock seamless data access.', - featureName: 'Index Patterns', - link: '/app/management/opensearch-dashboards/indexPatterns', - category: WORKSPACE_APP_CATEGORIES.getStarted, - }, - { - id: 'integrations', - featureDescription: 'Gain instant insights with pre-configured log dashboards.', - featureName: 'Integrations', - link: '/app/integrations', - category: WORKSPACE_APP_CATEGORIES.getStarted, - }, - // dashboardAndReport - { - id: 'dashboards', - featureDescription: 'Gain clarity and visibility with dynamic data visualization tools.', - featureName: 'Dashboards', - link: '/app/dashboards', - category: WORKSPACE_APP_CATEGORIES.dashboardAndReport, - }, - { - id: 'visualize', - featureDescription: - 'Unlock insightful data exploration with powerful visualization and aggregation tools.', - featureName: 'Visualizations', - link: '/app/visualize', - category: WORKSPACE_APP_CATEGORIES.dashboardAndReport, - }, - { - id: 'maps-dashboards', - featureDescription: 'Unlock spatial insights with multi-layer map visualizations.', - featureName: 'Maps', - link: '/app/maps-dashboards', - category: WORKSPACE_APP_CATEGORIES.dashboardAndReport, - }, - { - id: 'observability-notebooks', - featureDescription: 'Gain real-time visibility with dynamic, data-powered report generation.', - featureName: 'Notebooks', - link: '/app/observability-notebooks', - category: WORKSPACE_APP_CATEGORIES.dashboardAndReport, - }, - { - id: 'reports-dashboards', - featureDescription: 'Collaborate effectively with multi-format report sharing.', - featureName: 'Reports', - link: '/app/reports-dashboards', - category: WORKSPACE_APP_CATEGORIES.dashboardAndReport, - }, - // investigate - { - id: 'discover', - featureDescription: 'Uncover insights with raw data exploration.', - featureName: 'Discover', - link: '/app/data-explorer/discover', - category: WORKSPACE_APP_CATEGORIES.investigate, - }, - { - id: 'observability-traces', - featureDescription: 'Unveil performance bottlenecks with event flow visualization.', - featureName: 'Traces', - link: '/app/observability-traces', - category: WORKSPACE_APP_CATEGORIES.investigate, - }, - { - id: 'observability-metrics', - featureDescription: 'Transform logs into actionable visualizations with metric extraction.', - featureName: 'Metrics', - link: '/app/observability-metrics', - category: WORKSPACE_APP_CATEGORIES.investigate, - }, - { - id: 'observability-applications', - featureDescription: - 'Gain comprehensive system visibility with unified log, trace, and metric analysis.', - featureName: 'Applications', - link: '/app/observability-applications', - category: WORKSPACE_APP_CATEGORIES.investigate, - }, - // detect - { - id: 'alerting', - featureDescription: 'Proactively identify risks with customizable alter triggers.', - featureName: 'Alerts', - link: '/app/alerting', - category: WORKSPACE_APP_CATEGORIES.detect, - }, - { - id: 'anomaly-detection-dashboards', - featureDescription: 'Unveil anomalies with real-time data monitoring.', - featureName: 'Anomaly Detectors', - link: '/app/anomaly-detection-dashboards#/detectors', - category: WORKSPACE_APP_CATEGORIES.detect, - }, - { - id: 'opensearch_security_analytics_dashboards', - featureDescription: 'Receive timely notifications with detector-driven alert configuration.', - featureName: 'Threat Alerts', - link: '/app/opensearch_security_analytics_dashboards#/alerts', - category: WORKSPACE_APP_CATEGORIES.detect, - }, - { - id: 'opensearch_security_analytics_dashboards', - featureDescription: 'Proactively safeguard your systems with customizable detection rules.', - featureName: 'Threat Detectors', - link: '/app/opensearch_security_analytics_dashboards#/detectors', - category: WORKSPACE_APP_CATEGORIES.detect, - }, - { - id: 'opensearch_security_analytics_dashboards', - featureDescription: 'Tailor detection capabilities with flexible rule management.', - featureName: 'Detection Rules', - link: '/app/opensearch_security_analytics_dashboards#/rules', - category: WORKSPACE_APP_CATEGORIES.detect, - }, - { - id: 'opensearch_security_analytics_dashboards', - featureDescription: 'Detect multi-system threats with correlation rule builder.', - featureName: 'Correlations', - link: '/app/opensearch_security_analytics_dashboards#/correlations', - category: WORKSPACE_APP_CATEGORIES.detect, - }, - { - id: 'opensearch_security_analytics_dashboards', - featureDescription: 'Uncover hidden patterns and trends with detector finding analysis.', - featureName: 'Findings', - link: '/app/opensearch_security_analytics_dashboards#/findings', - category: WORKSPACE_APP_CATEGORIES.investigate, - }, - // build search solutions - { - id: 'searchRelevance', - featureDescription: 'Optimize query performance with side-by-side comparison.', - featureName: 'Compare Search Results', - link: '/app/searchRelevance', - category: WORKSPACE_APP_CATEGORIES.searchSolution, - }, -]; diff --git a/src/plugins/workspace/public/components/workspace_overview/getting_start_card.test.tsx b/src/plugins/workspace/public/components/workspace_overview/getting_start_card.test.tsx deleted file mode 100644 index 107568751cbc..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/getting_start_card.test.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { fireEvent, render } from '@testing-library/react'; -import React from 'react'; -import { WorkspaceOverviewCard } from './getting_start_card'; -import { coreMock } from '../../../../../core/public/mocks'; -import { DEFAULT_APP_CATEGORIES } from '../../../../../core/public'; -import { GetStartCard } from './types'; - -describe('WorkspaceOverviewCard', () => { - const featureName = 'Visualizations'; - const featureDescription = 'this is a description'; - const card = { - id: 'visualize', - featureDescription, - featureName, - link: '/app/visualize', - category: DEFAULT_APP_CATEGORIES.dashboardAndReport, - }; - const mockCoreStart = coreMock.createStart(); - const renderWorkspaceCard = (_card: GetStartCard) => { - return ( - - ); - }; - - it('render getting start card normally', async () => { - const { container } = render(renderWorkspaceCard(card)); - expect(container).toHaveTextContent(`with Visualizations`); - expect(container).toHaveTextContent(featureDescription); - }); - - it('click on card will navigate to related URL', async () => { - const { getByTestId } = render(renderWorkspaceCard(card)); - fireEvent.click(getByTestId(featureName)); - expect(mockCoreStart.application.getUrlForApp).not.toHaveBeenCalled(); - expect(mockCoreStart.application.navigateToUrl).toHaveBeenCalledWith( - 'http://localhost/w/test/app/visualize' - ); - }); - - it('click on card will navigate to specified app if no link provided', async () => { - const { getByTestId } = render(renderWorkspaceCard({ ...card, link: undefined })); - fireEvent.click(getByTestId(featureName)); - expect(mockCoreStart.application.getUrlForApp).toHaveBeenCalledWith('visualize'); - expect(mockCoreStart.application.navigateToUrl).toHaveBeenCalledWith( - 'http://localhost/w/test/app/visualize' - ); - }); -}); diff --git a/src/plugins/workspace/public/components/workspace_overview/getting_start_card.tsx b/src/plugins/workspace/public/components/workspace_overview/getting_start_card.tsx deleted file mode 100644 index a25451129fb0..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/getting_start_card.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiCard, EuiFlexGroup, EuiFlexItem, EuiText, EuiTextColor } from '@elastic/eui'; -import React from 'react'; -import { ApplicationStart, IBasePath } from 'opensearch-dashboards/public'; -import { FormattedMessage } from '@osd/i18n/react'; -import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; -import { GetStartCard } from './types'; - -export interface WorkspaceOverviewCardProps { - card: GetStartCard; - workspaceId: string; - basePath: IBasePath; - application: ApplicationStart; -} - -export const WorkspaceOverviewCard = ({ - card, - application, - workspaceId, - basePath, -}: WorkspaceOverviewCardProps) => { - return ( - -

{card.featureDescription}

- - } - description={''} - footer={ - - - - - - - - - - } - onClick={() => { - let url = card.link; - if (!url && card.id) { - url = application.getUrlForApp(card.id); - } - - if (workspaceId && url) { - application.navigateToUrl(formatUrlWithWorkspaceId(url, workspaceId, basePath)); - } - }} - /> - ); -}; diff --git a/src/plugins/workspace/public/components/workspace_overview/getting_start_modal.test.tsx b/src/plugins/workspace/public/components/workspace_overview/getting_start_modal.test.tsx deleted file mode 100644 index d63459a1dfe0..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/getting_start_modal.test.tsx +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { fireEvent, render } from '@testing-library/react'; -import React from 'react'; -import { coreMock } from '../../../../../core/public/mocks'; -import { - WorkspaceOverviewGettingStartModal, - WorkspaceOverviewGettingStartModalProps, -} from './getting_start_modal'; -import { GetStartCard } from './types'; -import { waitFor } from '@testing-library/dom'; -import { WORKSPACE_APP_CATEGORIES } from '../../../common/constants'; - -// see https://github.com/elastic/eui/issues/5271 as workaround to render EuiSelectable correctly -jest.mock('react-virtualized-auto-sizer', () => ({ children }: any) => - children({ height: 600, width: 300 }) -); - -describe('WorkspaceOverviewGettingStartModal', () => { - const mockCoreStart = coreMock.createStart(); - const closeModal = jest.fn(); - const renderWorkspaceCardModal = (cards: GetStartCard[]) => { - const props: WorkspaceOverviewGettingStartModalProps = { - availableCards: cards, - onCloseModal: closeModal, - application: mockCoreStart.application, - basePath: mockCoreStart.http.basePath, - workspaceId: 'foo', - }; - return ; - }; - - it('render getting start card modal normally with empty cards', async () => { - const { getByTestId } = render(renderWorkspaceCardModal([])); - await waitFor(() => expect(getByTestId('category_single_selection')).toHaveTextContent('All')); - }); - - it('render getting start card modal normally', async () => { - const cards = [ - { - id: 'home', - featureDescription: 'Discover pre-loaded datasets before adding your own.', - featureName: 'Sample Datasets', - link: '/app/home#/tutorial_directory', - category: WORKSPACE_APP_CATEGORIES.getStarted, - }, - { - id: 'dashboards', - featureDescription: 'Gain clarity and visibility with dynamic data visualization tools.', - featureName: 'Dashboards', - link: '/app/dashboards', - category: WORKSPACE_APP_CATEGORIES.dashboardAndReport, - }, - ]; - const { queryByText, getByTestId } = render(renderWorkspaceCardModal(cards)); - expect(getByTestId('category_single_selection')).toHaveTextContent('All'); - expect(getByTestId('category_single_selection')).toHaveTextContent('Get started'); - expect(getByTestId('category_single_selection')).toHaveTextContent('Dashboard and report'); - expect( - queryByText('Gain clarity and visibility with dynamic data visualization tools.') - ).not.toBeNull(); - expect(queryByText('Discover pre-loaded datasets before adding your own.')).not.toBeNull(); - }); - - it('click on category to filter cards', async () => { - const cards = [ - { - id: 'home', - featureDescription: 'Discover pre-loaded datasets before adding your own.', - featureName: 'Sample Datasets', - link: '/app/home#/tutorial_directory', - category: WORKSPACE_APP_CATEGORIES.getStarted, - }, - { - id: 'dashboards', - featureDescription: 'Gain clarity and visibility with dynamic data visualization tools.', - featureName: 'Dashboards', - link: '/app/dashboards', - category: WORKSPACE_APP_CATEGORIES.dashboardAndReport, - }, - ]; - const { queryByText, getByTitle } = render(renderWorkspaceCardModal(cards)); - // click `Get started` category - fireEvent.click(getByTitle('Get started')); - expect( - queryByText('Gain clarity and visibility with dynamic data visualization tools.') - ).toBeNull(); - expect(queryByText('Discover pre-loaded datasets before adding your own.')).not.toBeNull(); - - // click `Dashboard and report` category - fireEvent.click(getByTitle('Dashboard and report')); - expect( - queryByText('Gain clarity and visibility with dynamic data visualization tools.') - ).not.toBeNull(); - expect(queryByText('Discover pre-loaded datasets before adding your own.')).toBeNull(); - }); - - it('click on close will close the modal', async () => { - const { getByTestId } = render(renderWorkspaceCardModal([])); - fireEvent.click(getByTestId('close')); - expect(closeModal).toHaveBeenCalled(); - }); -}); diff --git a/src/plugins/workspace/public/components/workspace_overview/getting_start_modal.tsx b/src/plugins/workspace/public/components/workspace_overview/getting_start_modal.tsx deleted file mode 100644 index c2bfc104cc05..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/getting_start_modal.tsx +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { ReactNode, useState } from 'react'; -import { - EuiFlexItem, - EuiText, - slugify, - EuiTitle, - EuiSpacer, - EuiFlexGrid, - EuiModal, - EuiModalHeader, - EuiModalBody, - EuiModalHeaderTitle, - EuiModalFooter, - EuiButton, - EuiFlexGroup, - EuiPanel, - EuiSelectable, - EuiSelectableOption, -} from '@elastic/eui'; -import { WorkspaceOverviewCard, WorkspaceOverviewCardProps } from './getting_start_card'; -import { GetStartCard } from './types'; -import './index.scss'; - -export interface WorkspaceOverviewGettingStartModalProps - extends Omit { - onCloseModal: () => void; - availableCards: GetStartCard[]; -} - -export const WorkspaceOverviewGettingStartModal = ( - props: WorkspaceOverviewGettingStartModalProps -) => { - const ALL = 'All'; - const [selectedItemName, setSelectedItem] = useState(ALL); - const { onCloseModal, availableCards } = props; - - const categories: string[] = [ - ...new Set( - availableCards.map((card) => { - return card?.category?.label || ALL; - }) - ), - ]; - - const options: EuiSelectableOption[] = [ALL, ...categories].map((category) => { - return { - label: category, - checked: selectedItemName === category ? 'on' : undefined, - className: 'gettingStartCategoryItem', - }; - }); - - const categorySelection = ( - { - const selectedOption = newOptions.find((option) => option.checked === 'on'); - setSelectedItem(selectedOption?.label || ALL); - }} - singleSelection={true} - listProps={{ - bordered: false, - rowHeight: 48, - onFocusBadge: false, - windowProps: { - className: 'gettingStartCategoryItemList', - }, - }} - > - {(list) => { - return list; - }} - - ); - - const cardList: ReactNode[] = categories - .filter((category) => category === selectedItemName || selectedItemName === ALL) - .map((category) => { - const cards = availableCards.filter((card) => { - return card.category?.label === category; - }); - - return ( -
- -

{category}

-
- - - {cards.map((card) => { - return ( - - - - ); - })} - - -
- ); - }); - - return ( - - - -

Define your path forward

- Discover tailored solutions for your unique objectives -
-
- - - - - {categorySelection} - - - - {cardList} - - - - - - - Close - - -
- ); -}; diff --git a/src/plugins/workspace/public/components/workspace_overview/index.scss b/src/plugins/workspace/public/components/workspace_overview/index.scss deleted file mode 100644 index 5c878370220c..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/index.scss +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -.gettingStartModel { - width: calc(90vw - #{$euiSize}); -} - -.gettingStartModel_body { - overflow-y: auto; - height: calc(75vh - 200px); -} - -.gettingStartCategoryItem { - border: none !important; -} - -.gettingStartCategory { - div { - &:focus-within { - outline: none; - animation: none !important; - } - } -} - -.gettingStartCategoryItemList { - mask: none !important; -} diff --git a/src/plugins/workspace/public/components/workspace_overview/types.ts b/src/plugins/workspace/public/components/workspace_overview/types.ts deleted file mode 100644 index e9ba69402cc9..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/types.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { App } from 'opensearch-dashboards/public'; - -export interface GetStartCard extends Partial { - /** - * feature Name - */ - featureName: string; - /** - * card description - */ - featureDescription: string; - /** - * destination when the card been clicked - */ - link?: string; -} diff --git a/src/plugins/workspace/public/components/workspace_overview/workspace_overview.test.tsx b/src/plugins/workspace/public/components/workspace_overview/workspace_overview.test.tsx deleted file mode 100644 index 1746765405b2..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/workspace_overview.test.tsx +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import React from 'react'; -import { coreMock } from '../../../../../core/public/mocks'; -import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; -import { BehaviorSubject } from 'rxjs'; -import { PublicAppInfo, WorkspaceObject } from 'opensearch-dashboards/public'; -import { IS_WORKSPACE_OVERVIEW_COLLAPSED_KEY, WorkspaceOverview } from './workspace_overview'; - -// all applications -const PublicAPPInfoMap = new Map([ - ['alerting', { id: 'alerting', title: 'alerting' }], - ['home', { id: 'home', title: 'home' }], -]); - -const mockCoreStart = coreMock.createStart(); - -const createWorkspacesSetupContractMockWithValue = (workspace?: WorkspaceObject) => { - const currentWorkspace = workspace - ? workspace - : { - id: 'foo_id', - name: 'foo', - description: 'this is my foo workspace description', - features: ['alerting'], - color: '', - icon: '', - reserved: false, - }; - const currentWorkspaceId$ = new BehaviorSubject(currentWorkspace.id); - const workspaceList$ = new BehaviorSubject([currentWorkspace]); - const currentWorkspace$ = new BehaviorSubject(currentWorkspace); - const initialized$ = new BehaviorSubject(true); - return { - currentWorkspaceId$, - workspaceList$, - currentWorkspace$, - initialized$, - }; -}; - -const WorkspaceOverviewPage = (props: any) => { - const workspacesService = props.workspacesService || createWorkspacesSetupContractMockWithValue(); - const { Provider } = createOpenSearchDashboardsReactContext({ - ...mockCoreStart, - ...{ - application: { - ...mockCoreStart.application, - applications$: new BehaviorSubject>(PublicAPPInfoMap as any), - }, - workspaces: workspacesService, - savedObjects: { - ...mockCoreStart.savedObjects, - client: { - ...mockCoreStart.savedObjects.client, - find: jest.fn().mockResolvedValue({ - savedObjects: [], - }), - }, - }, - }, - }); - - return ( - - - - ); -}; - -const setLocalStorage = jest.fn(); -const localStorageMock = { - getItem: jest.fn(), - setItem: setLocalStorage, - removeItem: jest.fn(), - key: jest.fn(), - clear: jest.fn(), -}; - -describe('WorkspaceOverview', () => { - const localStorage = window.localStorage; - - beforeAll(() => { - // Mock localStorage globally - Object.defineProperty(window, 'localStorage', { - value: localStorageMock, - }); - }); - - afterAll(() => { - Object.defineProperty(window, 'localStorage', { - value: localStorage, - }); - }); - - it('render workspace overview page normally', async () => { - const { container } = render(WorkspaceOverviewPage({})); - expect(container).toMatchSnapshot(); - }); - - it('filter getting start cards when workspace features is `*`', async () => { - const workspaceObject = { - id: 'foo_id', - name: 'foo', - description: 'this is my foo workspace description', - features: ['*'], - color: '', - icon: '', - reserved: false, - }; - const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); - const { getByTestId } = render(WorkspaceOverviewPage({ workspacesService: workspaceService })); - expect(getByTestId('workspaceGetStartCards')).toHaveTextContent('Sample Datasets'); - // see more - expect(getByTestId('workspaceGetStartCards')).toHaveTextContent( - 'Explore more paths to kick-start your OpenSearch journey.' - ); - }); - - it('filter getting start cards when workspace features is subset of all features', async () => { - const workspaceObject = { - id: 'foo_id', - name: 'foo', - description: 'this is my foo workspace description', - features: ['alerting', 'home'], - color: '', - icon: '', - reserved: false, - }; - const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); - const { getByTestId } = render(WorkspaceOverviewPage({ workspacesService: workspaceService })); - expect(getByTestId('workspaceGetStartCards')).toHaveTextContent('with Sample Datasets'); - expect(getByTestId('workspaceGetStartCards')).toHaveTextContent('with Alerts'); - // no see more - expect(getByTestId('workspaceGetStartCards')).not.toHaveTextContent( - 'Explore more paths to kick-start your OpenSearch journey.' - ); - }); - - it('getting start section is expanded by default', async () => { - const workspaceObject = { - id: 'foo_id', - name: 'foo', - description: 'this is my foo workspace description', - features: ['alerting', 'home'], - color: '', - icon: '', - reserved: false, - }; - const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); - const { getByTestId } = render(WorkspaceOverviewPage({ workspacesService: workspaceService })); - expect(getByTestId('Collapse')).toBeVisible(); - }); - - it('getting start section visible setting will saved to localStorage', async () => { - const workspaceObject = { - id: 'foo_id', - name: 'foo', - description: 'this is my foo workspace description', - features: ['alerting', 'home'], - color: '', - icon: '', - reserved: false, - }; - const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); - const { getByTestId } = render(WorkspaceOverviewPage({ workspacesService: workspaceService })); - expect(getByTestId('Collapse')).toBeVisible(); - fireEvent.click(getByTestId('Collapse')); - expect(getByTestId('Expand')).toBeVisible(); - expect(localStorageMock.setItem).toHaveBeenCalledWith( - IS_WORKSPACE_OVERVIEW_COLLAPSED_KEY + '_foo_id', - 'true' - ); - // click on Collapse - fireEvent.click(getByTestId('Expand')); - expect(getByTestId('Collapse')).toBeVisible(); - expect(localStorageMock.setItem).toHaveBeenCalledWith( - IS_WORKSPACE_OVERVIEW_COLLAPSED_KEY + '_foo_id', - 'false' - ); - }); - - it('click on library tab will redirect to saved objects page', async () => { - const workspaceObject = { - id: 'foo_id', - name: 'foo', - description: 'this is my foo workspace description', - features: ['alerting', 'home'], - color: '', - icon: '', - reserved: false, - }; - const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); - const { getByText } = render(WorkspaceOverviewPage({ workspacesService: workspaceService })); - fireEvent.click(getByText('Library')); - - expect(mockCoreStart.application.navigateToApp).toHaveBeenCalledWith('management', { - path: 'opensearch-dashboards/objects', - }); - }); - - it('click on settings tab will show workspace update page', async () => { - const workspaceObject = { - id: 'foo_id', - name: 'foo', - description: 'this is my foo workspace description', - features: ['alerting', 'home'], - color: '', - icon: '', - reserved: false, - }; - const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); - const { getByText } = render(WorkspaceOverviewPage({ workspacesService: workspaceService })); - fireEvent.click(getByText('Settings')); - await waitFor(() => { - expect(screen.queryByText('Enter details')).not.toBeNull(); - // title is hidden - expect(screen.queryByText('Update Workspace')).toBeNull(); - }); - }); - - it('default selected tab is overview', async () => { - const workspaceObject = { - id: 'foo_id', - name: 'foo', - description: 'this is my foo workspace description', - features: ['alerting', 'home'], - color: '', - icon: '', - reserved: false, - }; - const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); - render(WorkspaceOverviewPage({ workspacesService: workspaceService })); - expect(document.querySelector('#overview')).toHaveClass('euiTab-isSelected'); - }); -}); diff --git a/src/plugins/workspace/public/components/workspace_overview/workspace_overview.tsx b/src/plugins/workspace/public/components/workspace_overview/workspace_overview.tsx deleted file mode 100644 index 63073bbce8c6..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/workspace_overview.tsx +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useState, useMemo, ReactNode, useEffect } from 'react'; -import { - EuiPage, - EuiPageBody, - EuiPageHeader, - EuiSpacer, - EuiFlexItem, - EuiText, - EuiTabbedContent, - EuiTitle, - EuiFlexGroup, - EuiPanel, - EuiButtonEmpty, -} from '@elastic/eui'; - -import { useObservable } from 'react-use'; -import { i18n } from '@osd/i18n'; -import { App, CoreStart, PublicAppInfo } from 'opensearch-dashboards/public'; -import { BehaviorSubject } from 'rxjs'; -import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { WorkspaceOverviewSettings } from './workspace_overview_settings'; -import { WorkspaceOverviewContent } from './workspace_overview_content'; -import { getStartCards } from './all_get_started_cards'; -import { isAppAccessibleInWorkspace } from '../../utils'; -import { WorkspaceOverviewCard } from './getting_start_card'; -import { WorkspaceOverviewGettingStartModal } from './getting_start_modal'; - -export const IS_WORKSPACE_OVERVIEW_COLLAPSED_KEY = 'workspace:overview_collapsed'; - -export interface WorkspaceOverviewProps { - workspaceConfigurableApps$?: BehaviorSubject; -} - -export const WorkspaceOverview = (props: WorkspaceOverviewProps) => { - const { - services: { workspaces, application, http }, - } = useOpenSearchDashboards(); - - const currentWorkspace = useObservable(workspaces.currentWorkspace$); - const currentWorkspaceId = useObservable(workspaces.currentWorkspaceId$); - - // workspace level setting - const workspaceOverviewCollapsedKey = `${IS_WORKSPACE_OVERVIEW_COLLAPSED_KEY}_${ - currentWorkspaceId || '' - }`; - - const [isModalVisible, setIsModalVisible] = useState(false); - const [isGettingStartCardsCollapsed, setIsGettingStartCardsCollapsed] = useState(false); - - useEffect(() => { - setIsGettingStartCardsCollapsed(localStorage.getItem(workspaceOverviewCollapsedKey) === 'true'); - }, [workspaceOverviewCollapsedKey]); - - /** - * all available cards based on workspace selected features - */ - const availableCards = useMemo(() => { - if (!currentWorkspace) return []; - return getStartCards.filter( - (card) => !card.id || isAppAccessibleInWorkspace(card as App, currentWorkspace) - ); - }, [currentWorkspace]); - - if (!currentWorkspace) { - return null; - } - - const pageTitle = ( - - {currentWorkspace?.name} - - ); - - const tabs = [ - { - id: 'overview', - name: i18n.translate('workspace.overview.tabTitle', { - defaultMessage: 'Overview', - }), - content: , - }, - { - id: 'library', - name: i18n.translate('workspace.overview.library.tabTitle', { - defaultMessage: 'Library', - }), - content: <>, - }, - { - id: 'settings', - name: i18n.translate('workspace.overview.setting.tabTitle', { - defaultMessage: 'Settings', - }), - content: , - }, - ]; - - const collapseButton = ( - { - const newValue = !isGettingStartCardsCollapsed; - setIsGettingStartCardsCollapsed(newValue); - localStorage.setItem(workspaceOverviewCollapsedKey, newValue ? 'true' : 'false'); - }} - > - {isGettingStartCardsCollapsed ? 'Expand' : 'Collapse'} - - ); - - const rightSideItems: ReactNode[] = isGettingStartCardsCollapsed ? [collapseButton] : []; - - return ( - <> - - - {!isGettingStartCardsCollapsed ? ( - <> - -

- {i18n.translate('workspace.overview.startWorking.title', { - defaultMessage: 'Start working', - })} -

-
- - - {availableCards.slice(0, 5).map((card, i) => { - return ( - - - - ); - })} - {availableCards.length > 5 ? ( - - { - setIsModalVisible(true); - }} - > - - {i18n.translate('workspace.overview.seeMore.description', { - defaultMessage: - 'Explore more paths to kick-start your OpenSearch journey.', - })} - - - - ) : null} - - - - {collapseButton} - - - ) : null} -
-
- - - { - if (tab.id === 'library') { - application.navigateToApp('management', { - path: 'opensearch-dashboards/objects', - }); - } - }} - /> - {isModalVisible ? ( - { - setIsModalVisible(false); - }} - availableCards={availableCards} - workspaceId={currentWorkspace.id} - basePath={http.basePath} - application={application} - /> - ) : null} - - - - ); -}; diff --git a/src/plugins/workspace/public/components/workspace_overview/workspace_overview_settings.tsx b/src/plugins/workspace/public/components/workspace_overview/workspace_overview_settings.tsx deleted file mode 100644 index 9515fab260c6..000000000000 --- a/src/plugins/workspace/public/components/workspace_overview/workspace_overview_settings.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { WorkspaceUpdater } from '../workspace_updater'; -import { WorkspaceOverviewProps } from './workspace_overview'; - -export const WorkspaceOverviewSettings = ({ - workspaceConfigurableApps$, -}: WorkspaceOverviewProps) => { - return ( - - ); -}; diff --git a/src/plugins/workspace/public/components/workspace_updater_app.tsx b/src/plugins/workspace/public/components/workspace_updater_app.tsx deleted file mode 100644 index ab106b5c4b7a..000000000000 --- a/src/plugins/workspace/public/components/workspace_updater_app.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useEffect } from 'react'; -import { I18nProvider } from '@osd/i18n/react'; -import { i18n } from '@osd/i18n'; -import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; -import { WorkspaceUpdater, WorkspaceUpdaterProps } from './workspace_updater'; - -export const WorkspaceUpdaterApp = (props: WorkspaceUpdaterProps) => { - const { - services: { chrome }, - } = useOpenSearchDashboards(); - - /** - * set breadcrumbs to chrome - */ - useEffect(() => { - chrome?.setBreadcrumbs([ - { - text: i18n.translate('workspace.workspaceUpdateTitle', { - defaultMessage: 'Update workspace', - }), - }, - ]); - }, [chrome]); - - return ( - - - - ); -}; diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 32cb8b492258..7af07fee7fed 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -10,7 +10,7 @@ import { workspaceClientMock, WorkspaceClientMock } from './workspace_client.moc import { applicationServiceMock, chromeServiceMock, coreMock } from '../../../core/public/mocks'; import { DEFAULT_NAV_GROUPS, AppNavLinkStatus } from '../../../core/public'; import { WorkspacePlugin } from './plugin'; -import { WORKSPACE_FATAL_ERROR_APP_ID, WORKSPACE_OVERVIEW_APP_ID } from '../common/constants'; +import { WORKSPACE_FATAL_ERROR_APP_ID, WORKSPACE_DETAIL_APP_ID } from '../common/constants'; import { savedObjectsManagementPluginMock } from '../../saved_objects_management/public/mocks'; import { managementPluginMock } from '../../management/public/mocks'; @@ -30,7 +30,7 @@ describe('Workspace plugin', () => { savedObjectsManagement: savedObjectManagementSetupMock, management: managementPluginMock.createSetupContract(), }); - expect(setupMock.application.register).toBeCalledTimes(5); + expect(setupMock.application.register).toBeCalledTimes(4); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(savedObjectManagementSetupMock.columns.register).toBeCalledTimes(1); }); @@ -43,7 +43,7 @@ describe('Workspace plugin', () => { workspacePlugin.start(coreStart); coreStart.workspaces.currentWorkspaceId$.next('foo'); expect(coreStart.savedObjects.client.setCurrentWorkspace).toHaveBeenCalledWith('foo'); - expect(setupMock.application.register).toBeCalledTimes(5); + expect(setupMock.application.register).toBeCalledTimes(4); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(workspaceClientMock.enterWorkspace).toBeCalledTimes(0); }); @@ -80,7 +80,7 @@ describe('Workspace plugin', () => { await workspacePlugin.setup(setupMock, { management: managementPluginMock.createSetupContract(), }); - expect(setupMock.application.register).toBeCalledTimes(5); + expect(setupMock.application.register).toBeCalledTimes(4); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(workspaceClientMock.enterWorkspace).toBeCalledWith('workspaceId'); expect(setupMock.getStartServices).toBeCalledTimes(1); @@ -137,7 +137,7 @@ describe('Workspace plugin', () => { management: managementPluginMock.createSetupContract(), }); currentAppIdSubscriber?.next(WORKSPACE_FATAL_ERROR_APP_ID); - expect(applicationStartMock.navigateToApp).toBeCalledWith(WORKSPACE_OVERVIEW_APP_ID); + expect(applicationStartMock.navigateToApp).toBeCalledWith(WORKSPACE_DETAIL_APP_ID); windowSpy.mockRestore(); }); @@ -173,7 +173,7 @@ describe('Workspace plugin', () => { ); }); - it('#start add workspace overview page to breadcrumbs when start', async () => { + it('#start add workspace detail page to breadcrumbs when start', async () => { const startMock = coreMock.createStart(); const workspaceObject = { id: 'foo', @@ -196,7 +196,7 @@ describe('Workspace plugin', () => { ); }); - it('#start do not add workspace overview page to breadcrumbs when already exists', async () => { + it('#start do not add workspace detail page to breadcrumbs when already exists', async () => { const startMock = coreMock.createStart(); const workspaceObject = { id: 'foo', diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 2b798b1c5073..a8fb32121ea8 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -24,9 +24,8 @@ import { } from '../../../core/public'; import { WORKSPACE_FATAL_ERROR_APP_ID, - WORKSPACE_OVERVIEW_APP_ID, + WORKSPACE_DETAIL_APP_ID, WORKSPACE_CREATE_APP_ID, - WORKSPACE_UPDATE_APP_ID, WORKSPACE_LIST_APP_ID, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; @@ -148,7 +147,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> } /** - * Add workspace overview page to breadcrumbs + * Add workspace detail page to breadcrumbs * @param core CoreStart * @private */ @@ -165,7 +164,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> const workspaceBreadcrumb: ChromeBreadcrumb = { text: currentWorkspace.name, onClick: () => { - core.application.navigateToApp(WORKSPACE_OVERVIEW_APP_ID); + core.application.navigateToApp(WORKSPACE_DETAIL_APP_ID); }, }; const homeBreadcrumb: ChromeBreadcrumb = { @@ -232,7 +231,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> const [{ application }] = await core.getStartServices(); const currentAppIdSubscription = application.currentAppId$.subscribe((currentAppId) => { if (currentAppId === WORKSPACE_FATAL_ERROR_APP_ID) { - application.navigateToApp(WORKSPACE_OVERVIEW_APP_ID); + application.navigateToApp(WORKSPACE_DETAIL_APP_ID); } currentAppIdSubscription.unsubscribe(); }); @@ -279,32 +278,17 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> }); /** - * register workspace overview page + * register workspace detail page */ core.application.register({ - id: WORKSPACE_OVERVIEW_APP_ID, - title: i18n.translate('workspace.settings.workspaceOverview', { - defaultMessage: 'Workspace Overview', + id: WORKSPACE_DETAIL_APP_ID, + title: i18n.translate('workspace.settings.workspaceDetail', { + defaultMessage: 'Workspace Detail', }), navLinkStatus: AppNavLinkStatus.hidden, async mount(params: AppMountParameters) { - const { renderOverviewApp } = await import('./application'); - return mountWorkspaceApp(params, renderOverviewApp); - }, - }); - - /** - * register workspace update page - */ - core.application.register({ - id: WORKSPACE_UPDATE_APP_ID, - title: i18n.translate('workspace.settings.workspaceUpdate', { - defaultMessage: 'Update Workspace', - }), - navLinkStatus: AppNavLinkStatus.hidden, - async mount(params: AppMountParameters) { - const { renderUpdaterApp } = await import('./application'); - return mountWorkspaceApp(params, renderUpdaterApp); + const { renderDetailApp } = await import('./application'); + return mountWorkspaceApp(params, renderDetailApp); }, }); From ac22fd2734d3e5d1498d8397b1b8639485bc136c Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 20:29:32 +0800 Subject: [PATCH 076/276] [navigation-next] Add new left navigation (#7230) (#7300) (#7301) * [navigation-next] Add CollapsibleNavGroupEnabled component into chrome_service.(#7093) * feat: enable parent nav link id * feat: modify left navigation * feat: modify style * feat: enable left bottom * temp: merge * feat: save * feat: merge * temp change * temp change * fix: overview page can not be load * feat: remove useless change * feat: add unit test * feat: update snapshot * fix: unit test error * fix: new application * feat: add unit test * feat: update category based on latest design * feat: update * feat: update snapshot * feat: do not emphasize see all link * Changeset file for PR #7230 created/updated * feat: update * feat: update --------- (cherry picked from commit b28aa983627592086827248d79034a68aa8b6196) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7230.yml | 2 + src/core/public/chrome/chrome_service.mock.ts | 2 + src/core/public/chrome/chrome_service.tsx | 5 +- src/core/public/chrome/index.ts | 2 +- .../nav_controls/nav_controls_service.test.ts | 20 + .../nav_controls/nav_controls_service.ts | 15 + ...ollapsible_nav_group_enabled.test.tsx.snap | 527 ++++++++++++++++++ .../header/__snapshots__/header.test.tsx.snap | 50 +- .../header/collapsible_nav_group_enabled.scss | 49 ++ .../collapsible_nav_group_enabled.test.tsx | 226 ++++++++ .../header/collapsible_nav_group_enabled.tsx | 347 ++++++++++++ ...collapsible_nav_group_enabled_top.test.tsx | 111 ++++ .../collapsible_nav_group_enabled_top.tsx | 116 ++++ .../public/chrome/ui/header/header.test.tsx | 19 +- src/core/public/chrome/ui/header/header.tsx | 81 ++- .../chrome/ui/header/header_nav_controls.tsx | 4 +- src/core/public/chrome/ui/header/nav_link.tsx | 4 +- src/core/public/index.ts | 2 + src/core/utils/default_app_categories.ts | 7 + .../mount_management_section.tsx | 39 +- .../advanced_settings/public/plugin.test.ts | 23 + .../advanced_settings/public/plugin.ts | 40 +- .../dashboard_listing.test.tsx.snap | 10 + .../dashboard_top_nav.test.tsx.snap | 12 + src/plugins/dashboard/public/plugin.test.tsx | 30 + src/plugins/dashboard/public/plugin.tsx | 39 +- .../mount_management_section.tsx | 39 +- .../data_source_management/public/plugin.ts | 81 ++- .../dev_tools/public/dev_tools_icon.tsx | 18 + src/plugins/dev_tools/public/plugin.ts | 14 +- src/plugins/discover/public/plugin.test.ts | 35 ++ src/plugins/discover/public/plugin.ts | 42 +- src/plugins/home/public/mocks/index.ts | 2 + src/plugins/home/public/plugin.test.mocks.ts | 2 + src/plugins/home/public/plugin.ts | 12 +- .../mount_management_section.tsx | 45 +- .../public/plugin.test.ts | 25 + .../index_pattern_management/public/plugin.ts | 76 ++- .../public/components/settings_icon.tsx | 61 ++ src/plugins/management/public/plugin.ts | 25 +- .../management_overview/public/plugin.ts | 4 + .../public/plugin.ts | 7 +- .../management_section/mount_section.tsx | 84 +-- .../saved_objects_management/public/plugin.ts | 68 ++- src/plugins/visualize/public/plugin.ts | 34 +- src/plugins/workspace/public/plugin.ts | 13 + 46 files changed, 2343 insertions(+), 126 deletions(-) create mode 100644 changelogs/fragments/7230.yml create mode 100644 src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap create mode 100644 src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss create mode 100644 src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx create mode 100644 src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx create mode 100644 src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.test.tsx create mode 100644 src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.tsx create mode 100644 src/plugins/advanced_settings/public/plugin.test.ts create mode 100644 src/plugins/dashboard/public/plugin.test.tsx create mode 100644 src/plugins/dev_tools/public/dev_tools_icon.tsx create mode 100644 src/plugins/discover/public/plugin.test.ts create mode 100644 src/plugins/index_pattern_management/public/plugin.test.ts create mode 100644 src/plugins/management/public/components/settings_icon.tsx diff --git a/changelogs/fragments/7230.yml b/changelogs/fragments/7230.yml new file mode 100644 index 000000000000..5a7be07b21ed --- /dev/null +++ b/changelogs/fragments/7230.yml @@ -0,0 +1,2 @@ +feat: +- [navigation-next] Add new left navigation ([#7230](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7230)) \ No newline at end of file diff --git a/src/core/public/chrome/chrome_service.mock.ts b/src/core/public/chrome/chrome_service.mock.ts index dd595c31f456..446b04d4d8b1 100644 --- a/src/core/public/chrome/chrome_service.mock.ts +++ b/src/core/public/chrome/chrome_service.mock.ts @@ -71,9 +71,11 @@ const createStartContractMock = () => { registerLeft: jest.fn(), registerCenter: jest.fn(), registerRight: jest.fn(), + registerLeftBottom: jest.fn(), getLeft$: jest.fn(), getCenter$: jest.fn(), getRight$: jest.fn(), + getLeftBottom$: jest.fn(), }, navGroup: { getNavGroupsMap$: jest.fn(() => new BehaviorSubject({})), diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx index 87a74d04c6d5..4f0fc7dc08e4 100644 --- a/src/core/public/chrome/chrome_service.tsx +++ b/src/core/public/chrome/chrome_service.tsx @@ -295,6 +295,7 @@ export class ChromeService { navControlsRight$={navControls.getRight$()} navControlsExpandedCenter$={navControls.getExpandedCenter$()} navControlsExpandedRight$={navControls.getExpandedRight$()} + navControlsLeftBottom$={navControls.getLeftBottom$()} onIsLockedUpdate={setIsNavDrawerLocked} isLocked$={getIsNavDrawerLocked$} branding={injectedMetadata.getBranding()} @@ -303,7 +304,9 @@ export class ChromeService { collapsibleNavHeaderRender={this.collapsibleNavHeaderRender} sidecarConfig$={sidecarConfig$} navGroupEnabled={navGroup.getNavGroupEnabled()} - currentNavgroup$={navGroup.getCurrentNavGroup$()} + currentNavGroup$={navGroup.getCurrentNavGroup$()} + navGroupsMap$={navGroup.getNavGroupsMap$()} + setCurrentNavGroup={navGroup.setCurrentNavGroup} /> ), diff --git a/src/core/public/chrome/index.ts b/src/core/public/chrome/index.ts index 437001977cab..62cc9cb76ec0 100644 --- a/src/core/public/chrome/index.ts +++ b/src/core/public/chrome/index.ts @@ -50,4 +50,4 @@ export { ChromeRecentlyAccessed, ChromeRecentlyAccessedHistoryItem } from './rec export { ChromeNavControl, ChromeNavControls } from './nav_controls'; export { ChromeDocTitle } from './doc_title'; export { RightNavigationOrder } from './constants'; -export { ChromeRegistrationNavLink, ChromeNavGroupUpdater } from './nav_group'; +export { ChromeRegistrationNavLink, ChromeNavGroupUpdater, NavGroupItemInMap } from './nav_group'; diff --git a/src/core/public/chrome/nav_controls/nav_controls_service.test.ts b/src/core/public/chrome/nav_controls/nav_controls_service.test.ts index 6e2a71537e17..a3d73168c789 100644 --- a/src/core/public/chrome/nav_controls/nav_controls_service.test.ts +++ b/src/core/public/chrome/nav_controls/nav_controls_service.test.ts @@ -143,4 +143,24 @@ describe('RecentlyAccessed#start()', () => { ]); }); }); + + describe('expanded left bottom controls', () => { + it('allows registration', async () => { + const navControls = getStart(); + const nc = { mount: jest.fn() }; + navControls.registerLeftBottom(nc); + expect(await navControls.getLeftBottom$().pipe(take(1)).toPromise()).toEqual([nc]); + }); + + it('sorts controls by order property', async () => { + const navControls = getStart(); + const nc1 = { mount: jest.fn(), order: 10 }; + const nc2 = { mount: jest.fn(), order: 0 }; + const nc3 = { mount: jest.fn(), order: 20 }; + navControls.registerLeftBottom(nc1); + navControls.registerLeftBottom(nc2); + navControls.registerLeftBottom(nc3); + expect(await navControls.getLeftBottom$().pipe(take(1)).toPromise()).toEqual([nc2, nc1, nc3]); + }); + }); }); diff --git a/src/core/public/chrome/nav_controls/nav_controls_service.ts b/src/core/public/chrome/nav_controls/nav_controls_service.ts index 57298dac39ff..19135cbf866c 100644 --- a/src/core/public/chrome/nav_controls/nav_controls_service.ts +++ b/src/core/public/chrome/nav_controls/nav_controls_service.ts @@ -62,12 +62,16 @@ export interface ChromeNavControls { registerRight(navControl: ChromeNavControl): void; /** Register a nav control to be presented on the top-center side of the chrome header. */ registerCenter(navControl: ChromeNavControl): void; + /** Register a nav control to be presented on the left-bottom side of the left navigation. */ + registerLeftBottom(navControl: ChromeNavControl): void; /** @internal */ getLeft$(): Observable; /** @internal */ getRight$(): Observable; /** @internal */ getCenter$(): Observable; + /** @internal */ + getLeftBottom$(): Observable; } /** @internal */ @@ -82,6 +86,7 @@ export class NavControlsService { const navControlsExpandedCenter$ = new BehaviorSubject>( new Set() ); + const navControlsLeftBottom$ = new BehaviorSubject>(new Set()); return { // In the future, registration should be moved to the setup phase. This @@ -105,6 +110,11 @@ export class NavControlsService { new Set([...navControlsExpandedCenter$.value.values(), navControl]) ), + registerLeftBottom: (navControl: ChromeNavControl) => + navControlsLeftBottom$.next( + new Set([...navControlsLeftBottom$.value.values(), navControl]) + ), + getLeft$: () => navControlsLeft$.pipe( map((controls) => sortBy([...controls.values()], 'order')), @@ -130,6 +140,11 @@ export class NavControlsService { map((controls) => sortBy([...controls.values()], 'order')), takeUntil(this.stop$) ), + getLeftBottom$: () => + navControlsLeftBottom$.pipe( + map((controls) => sortBy([...controls.values()], 'order')), + takeUntil(this.stop$) + ), }; } diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap new file mode 100644 index 000000000000..61fb739ad6c2 --- /dev/null +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap @@ -0,0 +1,527 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` should render correctly 1`] = ` +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+`; + +exports[` should render correctly 2`] = ` +
+
+
+
+
+
+
+
+
+
+
+`; + +exports[` should show all use case by default and able to click see all 1`] = ` +
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+
+`; + +exports[` should render correctly 1`] = ` +
+
+ +
+
+`; diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index ec32ff17cf95..597cb26f7e45 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -304,7 +304,7 @@ exports[`Header handles visibility and lock changes 1`] = ` "thrownError": null, } } - currentNavgroup$={ + currentNavGroup$={ BehaviorSubject { "_isScalar": false, "_value": undefined, @@ -1739,6 +1739,17 @@ exports[`Header handles visibility and lock changes 1`] = ` "thrownError": null, } } + navControlsLeftBottom$={ + BehaviorSubject { + "_isScalar": false, + "_value": Array [], + "closed": false, + "hasError": false, + "isStopped": false, + "observers": Array [], + "thrownError": null, + } + } navControlsRight$={ BehaviorSubject { "_isScalar": false, @@ -1789,6 +1800,17 @@ exports[`Header handles visibility and lock changes 1`] = ` } } navGroupEnabled={false} + navGroupsMap$={ + BehaviorSubject { + "_isScalar": false, + "_value": Object {}, + "closed": false, + "hasError": false, + "isStopped": false, + "observers": Array [], + "thrownError": null, + } + } navLinks$={ BehaviorSubject { "_isScalar": false, @@ -1977,6 +1999,7 @@ exports[`Header handles visibility and lock changes 1`] = ` "thrownError": null, } } + setCurrentNavGroup={[MockFunction]} sidecarConfig$={ BehaviorSubject { "_isScalar": false, @@ -7173,7 +7196,7 @@ exports[`Header renders condensed header 1`] = ` "thrownError": null, } } - currentNavgroup$={ + currentNavGroup$={ BehaviorSubject { "_isScalar": false, "_value": undefined, @@ -8490,6 +8513,17 @@ exports[`Header renders condensed header 1`] = ` "thrownError": null, } } + navControlsLeftBottom$={ + BehaviorSubject { + "_isScalar": false, + "_value": Array [], + "closed": false, + "hasError": false, + "isStopped": false, + "observers": Array [], + "thrownError": null, + } + } navControlsRight$={ BehaviorSubject { "_isScalar": false, @@ -8540,6 +8574,17 @@ exports[`Header renders condensed header 1`] = ` } } navGroupEnabled={false} + navGroupsMap$={ + BehaviorSubject { + "_isScalar": false, + "_value": Object {}, + "closed": false, + "hasError": false, + "isStopped": false, + "observers": Array [], + "thrownError": null, + } + } navLinks$={ BehaviorSubject { "_isScalar": false, @@ -8678,6 +8723,7 @@ exports[`Header renders condensed header 1`] = ` "thrownError": null, } } + setCurrentNavGroup={[MockFunction]} sidecarConfig$={ BehaviorSubject { "_isScalar": false, diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss new file mode 100644 index 000000000000..50e822bae295 --- /dev/null +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss @@ -0,0 +1,49 @@ +.context-nav-wrapper { + border: none !important; + + .nav-link-item { + padding: $ouiSize / 4 $ouiSize; + border-radius: $ouiSize; + box-shadow: none; + margin-bottom: 0; + margin-top: 0; + + &::after { + display: none; + } + + .nav-link-item-btn { + margin-bottom: 0; + + &::after { + display: none; + } + } + } + + .nav-nested-item { + .nav-link-item-btn { + padding-left: 0; + padding-right: 0; + } + } + + .left-navigation-wrapper { + display: flex; + flex-direction: column; + border-right: $ouiBorderThin; + } + + .scrollable-container { + flex: 1; + } + + .bottom-container { + padding: 0 $ouiSize; + display: flex; + } + + .nav-controls-padding { + padding: $ouiSize; + } +} diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx new file mode 100644 index 000000000000..b08029553b50 --- /dev/null +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx @@ -0,0 +1,226 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { BehaviorSubject } from 'rxjs'; +import { fireEvent, render } from '@testing-library/react'; +import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; +import { + CollapsibleNavGroupEnabled, + CollapsibleNavGroupEnabledProps, + NavGroups, +} from './collapsible_nav_group_enabled'; +import { ChromeNavLink } from '../../nav_links'; +import { ChromeRegistrationNavLink, NavGroupItemInMap } from '../../nav_group'; +import { httpServiceMock } from '../../../mocks'; +import { getLogos } from '../../../../common'; +import { ALL_USE_CASE_ID, DEFAULT_NAV_GROUPS } from '../../../../public'; +import { CollapsibleNavTopProps } from './collapsible_nav_group_enabled_top'; + +jest.mock('./collapsible_nav_group_enabled_top', () => ({ + CollapsibleNavTop: (props: CollapsibleNavTopProps) => ( + + ), +})); + +const mockBasePath = httpServiceMock.createSetupContract({ basePath: '/test' }).basePath; + +describe('', () => { + const getMockedNavLink = ( + navLink: Partial + ): ChromeNavLink & ChromeRegistrationNavLink => ({ + baseUrl: '', + href: '', + id: '', + title: '', + ...navLink, + }); + it('should render correctly', () => { + const navigateToApp = jest.fn(); + const onNavItemClick = jest.fn(); + const { container, getByTestId } = render( + + ); + expect(container).toMatchSnapshot(); + expect(container.querySelectorAll('.nav-link-item-btn').length).toEqual(5); + fireEvent.click(getByTestId('collapsibleNavAppLink-pure')); + expect(navigateToApp).toBeCalledWith('pure'); + }); +}); + +describe('', () => { + function mockProps( + props?: Partial & { + navGroupsMap?: Record; + } + ): CollapsibleNavGroupEnabledProps { + const currentNavGroup$ = new BehaviorSubject(undefined); + const navGroupsMap$ = new BehaviorSubject>({ + [ALL_USE_CASE_ID]: { + ...DEFAULT_NAV_GROUPS[ALL_USE_CASE_ID], + navLinks: [ + { + id: 'link-in-all', + title: 'link-in-all', + }, + ], + }, + [DEFAULT_NAV_GROUPS.observability.id]: { + ...DEFAULT_NAV_GROUPS.observability, + navLinks: [ + { + id: 'link-in-observability', + title: 'link-in-observability', + showInAllNavGroup: true, + }, + ], + }, + ...props?.navGroupsMap, + }); + return { + appId$: new BehaviorSubject('test'), + basePath: mockBasePath, + id: 'collapsibe-nav', + isLocked: false, + isNavOpen: false, + navLinks$: new BehaviorSubject([ + { + id: 'link-in-all', + title: 'link-in-all', + baseUrl: '', + href: '', + }, + { + id: 'link-in-observability', + title: 'link-in-observability', + baseUrl: '', + href: '', + }, + { + id: 'link-in-analytics', + title: 'link-in-analytics', + baseUrl: '', + href: '', + }, + ]), + storage: new StubBrowserStorage(), + onIsLockedUpdate: () => {}, + closeNav: () => {}, + navigateToApp: () => Promise.resolve(), + navigateToUrl: () => Promise.resolve(), + customNavLink$: new BehaviorSubject(undefined), + logos: getLogos({}, mockBasePath.serverBasePath), + navGroupsMap$, + navControlsLeftBottom$: new BehaviorSubject([]), + currentNavGroup$, + setCurrentNavGroup: (val: string | undefined) => { + if (val) { + const currentNavGroup = navGroupsMap$.getValue()[val]; + if (currentNavGroup) { + currentNavGroup$.next(currentNavGroup); + } + } else { + currentNavGroup$.next(undefined); + } + }, + ...props, + }; + } + it('should render correctly', () => { + const props = mockProps({ + isNavOpen: true, + navGroupsMap: { + [DEFAULT_NAV_GROUPS.analytics.id]: { + ...DEFAULT_NAV_GROUPS.analytics, + navLinks: [ + { + id: 'link-in-analytics', + title: 'link-in-analytics', + showInAllNavGroup: true, + }, + ], + }, + }, + }); + const { container } = render(); + expect(container).toMatchSnapshot(); + const { container: isNavOpenCloseContainer } = render( + + ); + expect(isNavOpenCloseContainer).toMatchSnapshot(); + }); + + it('should render correctly when only one visible use case is provided', () => { + const props = mockProps(); + const { getAllByTestId } = render(); + expect(getAllByTestId('collapsibleNavAppLink-link-in-observability').length).toEqual(1); + }); + + it('should show all use case by default and able to click see all', async () => { + const props = mockProps({ + navGroupsMap: { + [DEFAULT_NAV_GROUPS.analytics.id]: { + ...DEFAULT_NAV_GROUPS.analytics, + navLinks: [ + { + id: 'link-in-analytics', + title: 'link-in-analytics', + showInAllNavGroup: true, + }, + ], + }, + }, + }); + const { container, getAllByTestId, getByTestId } = render( + + ); + fireEvent.click(getAllByTestId('collapsibleNavAppLink-link-in-analytics')[1]); + expect(getAllByTestId('collapsibleNavAppLink-link-in-analytics').length).toEqual(1); + expect(container).toMatchSnapshot(); + fireEvent.click(getByTestId('back')); + expect(getAllByTestId('collapsibleNavAppLink-link-in-analytics').length).toEqual(2); + }); +}); diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx new file mode 100644 index 000000000000..0575dc997fc7 --- /dev/null +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx @@ -0,0 +1,347 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import './collapsible_nav_group_enabled.scss'; +import { + EuiFlexItem, + EuiFlyout, + EuiSideNavItemType, + EuiSideNav, + EuiPanel, + EuiText, + EuiHorizontalRule, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import React, { useMemo } from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import * as Rx from 'rxjs'; +import classNames from 'classnames'; +import { ChromeNavControl, ChromeNavLink } from '../..'; +import { NavGroupStatus } from '../../../../types'; +import { InternalApplicationStart } from '../../../application/types'; +import { HttpStart } from '../../../http'; +import { OnIsLockedUpdate } from './'; +import { createEuiListItem } from './nav_link'; +import type { Logos } from '../../../../common/types'; +import { + ChromeNavGroupServiceStartContract, + ChromeRegistrationNavLink, + NavGroupItemInMap, +} from '../../nav_group'; +import { + fulfillRegistrationLinksToChromeNavLinks, + getOrderedLinksOrCategories, + LinkItem, + LinkItemType, +} from '../../utils'; +import { ALL_USE_CASE_ID } from '../../../../../core/utils'; +import { CollapsibleNavTop } from './collapsible_nav_group_enabled_top'; +import { HeaderNavControls } from './header_nav_controls'; + +export interface CollapsibleNavGroupEnabledProps { + appId$: InternalApplicationStart['currentAppId$']; + basePath: HttpStart['basePath']; + id: string; + isLocked: boolean; + isNavOpen: boolean; + navLinks$: Rx.Observable; + storage?: Storage; + onIsLockedUpdate: OnIsLockedUpdate; + closeNav: () => void; + navigateToApp: InternalApplicationStart['navigateToApp']; + navigateToUrl: InternalApplicationStart['navigateToUrl']; + customNavLink$: Rx.Observable; + logos: Logos; + navGroupsMap$: Rx.Observable>; + navControlsLeftBottom$: Rx.Observable; + currentNavGroup$: Rx.Observable; + setCurrentNavGroup: ChromeNavGroupServiceStartContract['setCurrentNavGroup']; +} + +interface NavGroupsProps { + navLinks: ChromeNavLink[]; + suffix?: React.ReactElement; + style?: React.CSSProperties; + appId?: string; + navigateToApp: InternalApplicationStart['navigateToApp']; + onNavItemClick: ( + event: React.MouseEvent, + navItem: ChromeNavLink + ) => void; +} + +const titleForSeeAll = i18n.translate('core.ui.primaryNav.seeAllLabel', { + defaultMessage: 'See all...', +}); + +export function NavGroups({ + navLinks, + suffix, + style, + appId, + navigateToApp, + onNavItemClick, +}: NavGroupsProps) { + const createNavItem = ({ + link, + className, + }: { + link: ChromeNavLink; + className?: string; + }): EuiSideNavItemType<{}> => { + const euiListItem = createEuiListItem({ + link, + appId, + dataTestSubj: `collapsibleNavAppLink-${link.id}`, + navigateToApp, + onClick: (event) => { + onNavItemClick(event, link); + }, + }); + + return { + id: `${link.id}-${link.title}`, + name: {link.title}, + onClick: euiListItem.onClick, + href: euiListItem.href, + emphasize: euiListItem.isActive, + className: `nav-link-item ${className || ''}`, + buttonClassName: 'nav-link-item-btn', + 'data-test-subj': euiListItem['data-test-subj'], + 'aria-label': link.title, + }; + }; + const createSideNavItem = (navLink: LinkItem, className?: string): EuiSideNavItemType<{}> => { + if (navLink.itemType === LinkItemType.LINK) { + if (navLink.link.title === titleForSeeAll) { + const navItem = createNavItem({ + link: navLink.link, + }); + + return { + ...navItem, + name: {navItem.name}, + emphasize: false, + }; + } + + return createNavItem({ + link: navLink.link, + className, + }); + } + + if (navLink.itemType === LinkItemType.PARENT_LINK && navLink.link) { + return { + ...createNavItem({ link: navLink.link }), + forceOpen: true, + items: navLink.links.map((subNavLink) => createSideNavItem(subNavLink, 'nav-nested-item')), + }; + } + + if (navLink.itemType === LinkItemType.CATEGORY) { + return { + id: navLink.category?.id ?? '', + name:
{navLink.category?.label ?? ''}
, + items: navLink.links?.map((link) => createSideNavItem(link)), + 'aria-label': navLink.category?.label, + }; + } + + return {} as EuiSideNavItemType<{}>; + }; + const orderedLinksOrCategories = getOrderedLinksOrCategories(navLinks); + const sideNavItems = orderedLinksOrCategories + .map((navLink) => createSideNavItem(navLink)) + .filter((item): item is EuiSideNavItemType<{}> => !!item); + return ( + + + {suffix} + + ); +} + +export function CollapsibleNavGroupEnabled({ + basePath, + id, + isLocked, + isNavOpen, + storage = window.localStorage, + onIsLockedUpdate, + closeNav, + navigateToApp, + navigateToUrl, + logos, + setCurrentNavGroup, + ...observables +}: CollapsibleNavGroupEnabledProps) { + const navLinks = useObservable(observables.navLinks$, []).filter((link) => !link.hidden); + const appId = useObservable(observables.appId$, ''); + const navGroupsMap = useObservable(observables.navGroupsMap$, {}); + const currentNavGroup = useObservable(observables.currentNavGroup$, undefined); + + const onGroupClick = ( + e: React.MouseEvent, + group: NavGroupItemInMap + ) => { + const fulfilledLinks = fulfillRegistrationLinksToChromeNavLinks( + navGroupsMap[group.id]?.navLinks, + navLinks + ); + setCurrentNavGroup(group.id); + + // the `navGroupsMap[group.id]?.navLinks` has already been sorted + const firstLink = fulfilledLinks[0]; + if (firstLink) { + const propsForEui = createEuiListItem({ + link: firstLink, + appId, + dataTestSubj: 'collapsibleNavAppLink', + navigateToApp, + }); + propsForEui.onClick(e); + } + }; + + const navLinksForRender: ChromeNavLink[] = useMemo(() => { + if (currentNavGroup) { + return fulfillRegistrationLinksToChromeNavLinks( + navGroupsMap[currentNavGroup.id].navLinks || [], + navLinks + ); + } + + const visibleUseCases = Object.values(navGroupsMap).filter( + (group) => group.type === undefined && group.status !== NavGroupStatus.Hidden + ); + + if (visibleUseCases.length === 1) { + return fulfillRegistrationLinksToChromeNavLinks( + navGroupsMap[visibleUseCases[0].id].navLinks || [], + navLinks + ); + } + + const navLinksForAll: ChromeRegistrationNavLink[] = []; + + // Append all the links that do not have use case info to keep backward compatible + const linkIdsWithUseGroupInfo = Object.values(navGroupsMap).reduce((total, navGroup) => { + return [...total, ...navGroup.navLinks.map((navLink) => navLink.id)]; + }, [] as string[]); + navLinks + .filter((link) => !linkIdsWithUseGroupInfo.includes(link.id)) + .forEach((navLink) => { + navLinksForAll.push(navLink); + }); + + // Append all the links registered to all use case + navGroupsMap[ALL_USE_CASE_ID]?.navLinks.forEach((navLink) => { + navLinksForAll.push(navLink); + }); + + // Append use case section into left navigation + Object.values(navGroupsMap) + .filter((group) => !group.type) + .forEach((group) => { + const categoryInfo = { + id: group.id, + label: group.title, + order: group.order, + }; + const linksForAllUseCaseWithinNavGroup = group.navLinks + .filter((navLink) => navLink.showInAllNavGroup) + .map((navLink) => ({ + ...navLink, + category: categoryInfo, + })); + + navLinksForAll.push(...linksForAllUseCaseWithinNavGroup); + + if (linksForAllUseCaseWithinNavGroup.length) { + navLinksForAll.push({ + id: group.navLinks[0].id, + title: titleForSeeAll, + order: Number.MAX_SAFE_INTEGER, + category: categoryInfo, + }); + } + }); + + return fulfillRegistrationLinksToChromeNavLinks(navLinksForAll, navLinks); + }, [navLinks, navGroupsMap, currentNavGroup]); + + const width = useMemo(() => { + if (!isNavOpen) { + return 50; + } + + return 270; + }, [isNavOpen]); + + return ( + +
+
+ + {!isNavOpen ? null : ( + <> + setCurrentNavGroup(undefined)} + currentNavGroup={currentNavGroup} + shouldShrinkNavigation={!isNavOpen} + onClickShrink={closeNav} + /> + { + if (navItem.title === titleForSeeAll && navItem.category?.id) { + const navGroup = navGroupsMap[navItem.category.id]; + onGroupClick(event, navGroup); + } + }} + appId={appId} + /> + + )} + +
+ +
+ +
+
+
+ ); +} diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.test.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.test.tsx new file mode 100644 index 000000000000..294992c3926f --- /dev/null +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.test.tsx @@ -0,0 +1,111 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { ChromeNavLink } from '../../nav_links'; +import { ChromeRegistrationNavLink } from '../../nav_group'; +import { httpServiceMock } from '../../../mocks'; +import { getLogos } from '../../../../common'; +import { CollapsibleNavTop } from './collapsible_nav_group_enabled_top'; + +const mockBasePath = httpServiceMock.createSetupContract({ basePath: '/test' }).basePath; + +describe('', () => { + const getMockedNavLink = ( + navLink: Partial + ): ChromeNavLink & ChromeRegistrationNavLink => ({ + baseUrl: '', + href: '', + id: '', + title: '', + ...navLink, + }); + const mockedNavLinks = [ + getMockedNavLink({ + id: 'home', + title: 'home link', + }), + getMockedNavLink({ + id: 'subLink', + title: 'subLink', + parentNavLinkId: 'pure', + }), + getMockedNavLink({ + id: 'link-in-category', + title: 'link-in-category', + category: { + id: 'category-1', + label: 'category-1', + }, + }), + getMockedNavLink({ + id: 'link-in-category-2', + title: 'link-in-category-2', + category: { + id: 'category-1', + label: 'category-1', + }, + }), + getMockedNavLink({ + id: 'sub-link-in-category', + title: 'sub-link-in-category', + parentNavLinkId: 'link-in-category', + category: { + id: 'category-1', + label: 'category-1', + }, + }), + ]; + const getMockedProps = () => { + return { + navLinks: mockedNavLinks, + navigateToApp: jest.fn(), + navGroupsMap: {}, + logos: getLogos({}, mockBasePath.serverBasePath), + shouldShrinkNavigation: false, + }; + }; + it('should render home icon', async () => { + const { findByTestId } = render(); + await findByTestId('collapsibleNavHome'); + }); + + it('should render back icon', async () => { + const { findByTestId } = render( + + ); + await findByTestId('collapsibleNavBackButton'); + }); + + it('should render expand icon', async () => { + const { findByTestId } = render( + + ); + await findByTestId('collapsibleNavShrinkButton'); + }); +}); diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.tsx new file mode 100644 index 000000000000..9e89155a8e4e --- /dev/null +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.tsx @@ -0,0 +1,116 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useMemo } from 'react'; +import { Logos } from 'opensearch-dashboards/public'; +import { + EuiButtonEmpty, + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiSpacer, +} from '@elastic/eui'; +import { InternalApplicationStart } from 'src/core/public/application'; +import { i18n } from '@osd/i18n'; +import { createEuiListItem } from './nav_link'; +import { NavGroupItemInMap } from '../../nav_group'; +import { ChromeNavLink } from '../../nav_links'; + +export interface CollapsibleNavTopProps { + navLinks: ChromeNavLink[]; + navGroupsMap: Record; + currentNavGroup?: NavGroupItemInMap; + navigateToApp: InternalApplicationStart['navigateToApp']; + logos: Logos; + onClickBack?: () => void; + onClickShrink?: () => void; + shouldShrinkNavigation: boolean; +} + +export const CollapsibleNavTop = ({ + navLinks, + navGroupsMap, + currentNavGroup, + navigateToApp, + logos, + onClickBack, + onClickShrink, + shouldShrinkNavigation, +}: CollapsibleNavTopProps) => { + const homeLink = useMemo(() => navLinks.find((link) => link.id === 'home'), [navLinks]); + + const shouldShowBackButton = useMemo( + () => + !shouldShrinkNavigation && + Object.values(navGroupsMap).filter((item) => !item.type).length > 1 && + currentNavGroup, + [navGroupsMap, currentNavGroup, shouldShrinkNavigation] + ); + + const shouldShowHomeLink = useMemo(() => { + if (!homeLink || shouldShrinkNavigation) return false; + + return !shouldShowBackButton; + }, [shouldShowBackButton, homeLink, shouldShrinkNavigation]); + + const homeLinkProps = useMemo(() => { + if (shouldShowHomeLink) { + const propsForHomeIcon = createEuiListItem({ + link: homeLink as ChromeNavLink, + appId: 'home', + dataTestSubj: 'collapsibleNavHome', + navigateToApp, + }); + return { + 'data-test-subj': propsForHomeIcon['data-test-subj'], + onClick: propsForHomeIcon.onClick, + href: propsForHomeIcon.href, + }; + } + + return {}; + }, [shouldShowHomeLink, homeLink, navigateToApp]); + + return ( +
+ + + {shouldShowHomeLink ? ( + + + + + + ) : null} + {shouldShowBackButton ? ( + + + + {i18n.translate('core.ui.primaryNav.backButtonLabel', { + defaultMessage: 'Back', + })} + + + ) : null} + + + + + +
+ ); +}; diff --git a/src/core/public/chrome/ui/header/header.test.tsx b/src/core/public/chrome/ui/header/header.test.tsx index ee4d660e1dd3..16e77a353cc6 100644 --- a/src/core/public/chrome/ui/header/header.test.tsx +++ b/src/core/public/chrome/ui/header/header.test.tsx @@ -78,7 +78,10 @@ function mockProps() { paddingSize: 640, }), navGroupEnabled: false, - currentNavgroup$: new BehaviorSubject(undefined), + currentNavGroup$: new BehaviorSubject(undefined), + navGroupsMap$: new BehaviorSubject({}), + navControlsLeftBottom$: new BehaviorSubject([]), + setCurrentNavGroup: jest.fn(() => {}), }; } @@ -168,4 +171,18 @@ describe('Header', () => { expect(component).toMatchSnapshot(); }); + + it('renders new header when feature flag is turned on', () => { + const branding = { + useExpandedHeader: false, + }; + const props = { + ...mockProps(), + branding, + }; + + const component = mountWithIntl(
); + + expect(component.find('CollapsibleNavGroupEnabled').exists()).toBeTruthy(); + }); }); diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index 7fd2b8d82080..06767103509b 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -66,7 +66,8 @@ import { HeaderActionMenu } from './header_action_menu'; import { HeaderLogo } from './header_logo'; import type { Logos } from '../../../../common/types'; import { ISidecarConfig, getOsdSidecarPaddingStyle } from '../../../overlays'; -import { NavGroupItemInMap } from '../../nav_group'; +import { CollapsibleNavGroupEnabled } from './collapsible_nav_group_enabled'; +import { ChromeNavGroupServiceStartContract, NavGroupItemInMap } from '../../nav_group'; export interface HeaderProps { opensearchDashboardsVersion: string; application: InternalApplicationStart; @@ -88,6 +89,7 @@ export interface HeaderProps { navControlsRight$: Observable; navControlsExpandedCenter$: Observable; navControlsExpandedRight$: Observable; + navControlsLeftBottom$: Observable; basePath: HttpStart['basePath']; isLocked$: Observable; loadingCount$: ReturnType; @@ -97,7 +99,9 @@ export interface HeaderProps { survey: string | undefined; sidecarConfig$: Observable; navGroupEnabled: boolean; - currentNavgroup$: Observable; + currentNavGroup$: Observable; + navGroupsMap$: Observable>; + setCurrentNavGroup: ChromeNavGroupServiceStartContract['setCurrentNavGroup']; } export function Header({ @@ -112,6 +116,7 @@ export function Header({ logos, collapsibleNavHeaderRender, navGroupEnabled, + setCurrentNavGroup, ...observables }: HeaderProps) { const isVisible = useObservable(observables.isVisible$, false); @@ -225,7 +230,7 @@ export function Header({ @@ -260,28 +265,54 @@ export function Header({
- { - setIsNavOpen(false); - if (toggleCollapsibleNavRef.current) { - toggleCollapsibleNavRef.current.focus(); - } - }} - customNavLink$={observables.customNavLink$} - logos={logos} - /> + {navGroupEnabled ? ( + { + setIsNavOpen(false); + if (toggleCollapsibleNavRef.current) { + toggleCollapsibleNavRef.current.focus(); + } + }} + customNavLink$={observables.customNavLink$} + logos={logos} + navGroupsMap$={observables.navGroupsMap$} + navControlsLeftBottom$={observables.navControlsLeftBottom$} + currentNavGroup$={observables.currentNavGroup$} + setCurrentNavGroup={setCurrentNavGroup} + /> + ) : ( + { + setIsNavOpen(false); + if (toggleCollapsibleNavRef.current) { + toggleCollapsibleNavRef.current.focus(); + } + }} + customNavLink$={observables.customNavLink$} + logos={logos} + /> + )} ); diff --git a/src/core/public/chrome/ui/header/header_nav_controls.tsx b/src/core/public/chrome/ui/header/header_nav_controls.tsx index 82ac5792a1cd..6f6fc50eadb9 100644 --- a/src/core/public/chrome/ui/header/header_nav_controls.tsx +++ b/src/core/public/chrome/ui/header/header_nav_controls.tsx @@ -38,9 +38,10 @@ import { HeaderExtension } from './header_extension'; interface Props { navControls$: Observable; side?: 'left' | 'right'; + className?: HTMLElement['className']; } -export function HeaderNavControls({ navControls$, side }: Props) { +export function HeaderNavControls({ navControls$, side, className }: Props) { const navControls = useObservable(navControls$, []); if (!navControls) { @@ -55,6 +56,7 @@ export function HeaderNavControls({ navControls$, side }: Props) { diff --git a/src/core/public/chrome/ui/header/nav_link.tsx b/src/core/public/chrome/ui/header/nav_link.tsx index 7f849df9b8ec..a80ce86507aa 100644 --- a/src/core/public/chrome/ui/header/nav_link.tsx +++ b/src/core/public/chrome/ui/header/nav_link.tsx @@ -53,7 +53,7 @@ interface Props { appId?: string; basePath?: HttpStart['basePath']; dataTestSubj: string; - onClick?: Function; + onClick?: (event: React.MouseEvent) => void; navigateToApp: CoreStart['application']['navigateToApp']; externalLink?: boolean; } @@ -79,7 +79,7 @@ export function createEuiListItem({ /* Use href and onClick to support "open in new tab" and SPA navigation in the same link */ onClick(event: React.MouseEvent) { if (!isModifiedOrPrevented(event)) { - onClick(); + onClick(event); } if ( diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 92a3525e03de..dd01046cbc62 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -73,6 +73,7 @@ import { RightNavigationButtonProps, ChromeRegistrationNavLink, ChromeNavGroupUpdater, + NavGroupItemInMap, } from './chrome'; import { FatalErrorsSetup, FatalErrorsStart, FatalErrorInfo } from './fatal_errors'; import { HttpSetup, HttpStart } from './http'; @@ -373,6 +374,7 @@ export { RightNavigationButtonProps, ChromeRegistrationNavLink, ChromeNavGroupUpdater, + NavGroupItemInMap, }; export { __osdBootstrap__ } from './osd_bootstrap'; diff --git a/src/core/utils/default_app_categories.ts b/src/core/utils/default_app_categories.ts index 49277b894d12..d22dbaf1b7ac 100644 --- a/src/core/utils/default_app_categories.ts +++ b/src/core/utils/default_app_categories.ts @@ -108,4 +108,11 @@ export const DEFAULT_APP_CATEGORIES: Record = Object.freeze }), order: 3000, }, + manage: { + id: 'manage', + label: i18n.translate('core.ui.manageNav.label', { + defaultMessage: 'Manage', + }), + order: 7000, + }, }); diff --git a/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx b/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx index 7fa0b9ddd2c0..fff7a9f1b357 100644 --- a/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx +++ b/src/plugins/advanced_settings/public/management_app/mount_management_section.tsx @@ -36,6 +36,7 @@ import { i18n } from '@osd/i18n'; import { I18nProvider } from '@osd/i18n/react'; import { StartServicesAccessor } from 'src/core/public'; +import { EuiPageContent } from '@elastic/eui'; import { AdvancedSettings } from './advanced_settings'; import { ManagementAppMountParams } from '../../../management/public'; import { ComponentRegistry } from '../types'; @@ -59,7 +60,7 @@ const readOnlyBadge = { export async function mountManagementSection( getStartServices: StartServicesAccessor, - params: ManagementAppMountParams, + params: ManagementAppMountParams & { wrapInPage?: boolean }, componentRegistry: ComponentRegistry['start'] ) { params.setBreadcrumbs(crumb); @@ -71,21 +72,31 @@ export async function mountManagementSection( chrome.setBadge(readOnlyBadge); } + const content = ( + + + + + + + + ); + ReactDOM.render( - - - - - - - + {params.wrapInPage ? ( + + {content} + + ) : ( + content + )} , params.element ); diff --git a/src/plugins/advanced_settings/public/plugin.test.ts b/src/plugins/advanced_settings/public/plugin.test.ts new file mode 100644 index 000000000000..2ff2a08b8077 --- /dev/null +++ b/src/plugins/advanced_settings/public/plugin.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { managementPluginMock } from '../../management/public/mocks'; +import { coreMock } from '../../../core/public/mocks'; +import { AdvancedSettingsPlugin } from './plugin'; +import { homePluginMock } from '../../home/public/mocks'; + +describe('AdvancedSettingsPlugin', () => { + it('setup successfully', () => { + const pluginInstance = new AdvancedSettingsPlugin(); + const setupMock = coreMock.createSetup(); + expect(() => + pluginInstance.setup(setupMock, { + management: managementPluginMock.createSetupContract(), + home: homePluginMock.createSetupContract(), + }) + ).not.toThrow(); + expect(setupMock.application.register).toBeCalledTimes(1); + }); +}); diff --git a/src/plugins/advanced_settings/public/plugin.ts b/src/plugins/advanced_settings/public/plugin.ts index 608bfc6a25e7..823ec62d5b12 100644 --- a/src/plugins/advanced_settings/public/plugin.ts +++ b/src/plugins/advanced_settings/public/plugin.ts @@ -29,10 +29,11 @@ */ import { i18n } from '@osd/i18n'; -import { CoreSetup, Plugin } from 'opensearch-dashboards/public'; +import { AppMountParameters, CoreSetup, Plugin } from 'opensearch-dashboards/public'; import { FeatureCatalogueCategory } from '../../home/public'; import { ComponentRegistry } from './component_registry'; import { AdvancedSettingsSetup, AdvancedSettingsStart, AdvancedSettingsPluginSetup } from './types'; +import { DEFAULT_NAV_GROUPS, AppNavLinkStatus } from '../../../core/public'; const component = new ComponentRegistry(); @@ -40,6 +41,10 @@ const title = i18n.translate('advancedSettings.advancedSettingsLabel', { defaultMessage: 'Advanced settings', }); +const titleInGroup = i18n.translate('advancedSettings.applicationSettingsLabel', { + defaultMessage: 'Application settings', +}); + export class AdvancedSettingsPlugin implements Plugin { public setup(core: CoreSetup, { management, home }: AdvancedSettingsPluginSetup) { @@ -57,6 +62,39 @@ export class AdvancedSettingsPlugin }, }); + core.application.register({ + id: 'settings', + title, + navLinkStatus: core.chrome.navGroup.getNavGroupEnabled() + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + mount: async (params: AppMountParameters) => { + const { mountManagementSection } = await import( + './management_app/mount_management_section' + ); + const [coreStart] = await core.getStartServices(); + + return mountManagementSection( + core.getStartServices, + { + ...params, + basePath: core.http.basePath.get(), + setBreadcrumbs: coreStart.chrome.setBreadcrumbs, + wrapInPage: true, + }, + component.start + ); + }, + }); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [ + { + id: 'settings', + title: titleInGroup, + order: 100, + }, + ]); + if (home) { home.featureCatalogue.register({ id: 'advanced_settings', diff --git a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap index 1e4da53a8aad..215591e2d4c5 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap @@ -214,9 +214,11 @@ exports[`dashboard listing hideWriteControls 1`] = ` "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -1399,9 +1401,11 @@ exports[`dashboard listing render table listing with initial filters from URL 1` "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -2645,9 +2649,11 @@ exports[`dashboard listing renders call to action when no dashboards exist 1`] = "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -3891,9 +3897,11 @@ exports[`dashboard listing renders table rows 1`] = ` "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -5137,9 +5145,11 @@ exports[`dashboard listing renders warning when listingLimit is exceeded 1`] = ` "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap index bfb7ce3ac695..acc6217ab4f9 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap @@ -202,9 +202,11 @@ exports[`Dashboard top nav render in embed mode 1`] = ` "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -1209,9 +1211,11 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -2216,9 +2220,11 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -3223,9 +3229,11 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -4230,9 +4238,11 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { @@ -5237,9 +5247,11 @@ exports[`Dashboard top nav render with all components 1`] = ` "navControls": Object { "getCenter$": [MockFunction], "getLeft$": [MockFunction], + "getLeftBottom$": [MockFunction], "getRight$": [MockFunction], "registerCenter": [MockFunction], "registerLeft": [MockFunction], + "registerLeftBottom": [MockFunction], "registerRight": [MockFunction], }, "navGroup": Object { diff --git a/src/plugins/dashboard/public/plugin.test.tsx b/src/plugins/dashboard/public/plugin.test.tsx new file mode 100644 index 000000000000..5ca81d5b77e8 --- /dev/null +++ b/src/plugins/dashboard/public/plugin.test.tsx @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { coreMock } from '../../../core/public/mocks'; +import { DashboardPlugin } from './plugin'; +import { dataPluginMock } from '../../data/public/mocks'; +import { embeddablePluginMock } from '../../embeddable/public/mocks'; +import { opensearchDashboardsLegacyPluginMock } from '../../opensearch_dashboards_legacy/public/mocks'; +import { urlForwardingPluginMock } from '../../url_forwarding/public/mocks'; +import { uiActionsPluginMock } from '../../ui_actions/public/mocks'; + +describe('DashboardPlugin', () => { + it('setup successfully', () => { + const setupMock = coreMock.createSetup(); + const initializerContext = coreMock.createPluginInitializerContext(); + const pluginInstance = new DashboardPlugin(initializerContext); + expect(() => + pluginInstance.setup(setupMock, { + data: dataPluginMock.createSetupContract(), + embeddable: embeddablePluginMock.createSetupContract(), + opensearchDashboardsLegacy: opensearchDashboardsLegacyPluginMock.createSetupContract(), + urlForwarding: urlForwardingPluginMock.createSetupContract(), + uiActions: uiActionsPluginMock.createSetupContract(), + }) + ).not.toThrow(); + expect(setupMock.chrome.navGroup.addNavLinksToGroup).toBeCalledTimes(5); + }); +}); diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index dd874d3419f2..afa3b6daf281 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -84,7 +84,7 @@ import { OpenSearchDashboardsLegacyStart, } from '../../opensearch_dashboards_legacy/public'; import { FeatureCatalogueCategory, HomePublicPluginSetup } from '../../../plugins/home/public'; -import { DEFAULT_APP_CATEGORIES } from '../../../core/public'; +import { DEFAULT_APP_CATEGORIES, DEFAULT_NAV_GROUPS } from '../../../core/public'; import { ACTION_CLONE_PANEL, @@ -452,6 +452,43 @@ export class DashboardPlugin }; core.application.register(app); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ + { + id: app.id, + order: 300, + category: undefined, + }, + ]); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ + { + id: app.id, + order: 300, + category: undefined, + }, + ]); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.analytics, [ + { + id: app.id, + order: 300, + category: undefined, + }, + ]); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [ + { + id: app.id, + order: 300, + category: undefined, + }, + ]); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ + { + id: app.id, + order: 300, + category: undefined, + }, + ]); + urlForwarding.forwardApp( DashboardConstants.DASHBOARDS_ID, DashboardConstants.DASHBOARDS_ID, diff --git a/src/plugins/data_source_management/public/management_app/mount_management_section.tsx b/src/plugins/data_source_management/public/management_app/mount_management_section.tsx index 6487d60c934b..a2b129ae4478 100644 --- a/src/plugins/data_source_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/data_source_management/public/management_app/mount_management_section.tsx @@ -10,6 +10,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Route, Router, Switch } from 'react-router-dom'; import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { EuiPageContent } from '@elastic/eui'; import { ManagementAppMountParams } from '../../../management/public'; import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; @@ -25,7 +26,7 @@ export interface DataSourceManagementStartDependencies { export async function mountManagementSection( getStartServices: StartServicesAccessor, - params: ManagementAppMountParams, + params: ManagementAppMountParams & { wrapInPage?: boolean }, authMethodsRegistry: AuthenticationMethodRegistry ) { const [ @@ -45,22 +46,32 @@ export async function mountManagementSection( authenticationMethodRegistry: authMethodsRegistry, }; + const content = ( + + + + + + + + + + + + + + ); + ReactDOM.render( - - - - - - - - - - - - - + {params.wrapInPage ? ( + + {content} + + ) : ( + content + )} , params.element diff --git a/src/plugins/data_source_management/public/plugin.ts b/src/plugins/data_source_management/public/plugin.ts index dbbe22cf48ed..d2f4ac55c889 100644 --- a/src/plugins/data_source_management/public/plugin.ts +++ b/src/plugins/data_source_management/public/plugin.ts @@ -4,7 +4,14 @@ */ import { DataSourcePluginSetup } from 'src/plugins/data_source/public'; -import { CoreSetup, CoreStart, Plugin } from '../../../core/public'; +import { + AppMountParameters, + CoreSetup, + CoreStart, + DEFAULT_APP_CATEGORIES, + DEFAULT_NAV_GROUPS, + Plugin, +} from '../../../core/public'; import { PLUGIN_NAME } from '../common'; import { createDataSourceSelector } from './components/data_source_selector/create_data_source_selector'; @@ -94,6 +101,78 @@ export class DataSourceManagementPlugin }, }); + /** + * The data sources features in observability has the same name as `DSM_APP_ID` + * Add a suffix to avoid duplication + */ + const DSM_APP_ID_FOR_STANDARD_APPLICATION = `${DSM_APP_ID}_core`; + + if (core.chrome.navGroup.getNavGroupEnabled()) { + core.application.register({ + id: DSM_APP_ID_FOR_STANDARD_APPLICATION, + title: PLUGIN_NAME, + order: 100, + mount: async (params: AppMountParameters) => { + const { mountManagementSection } = await import('./management_app'); + const [coreStart] = await core.getStartServices(); + + return mountManagementSection( + core.getStartServices, + { + ...params, + basePath: core.http.basePath.get(), + setBreadcrumbs: coreStart.chrome.setBreadcrumbs, + wrapInPage: true, + }, + this.authMethodsRegistry + ); + }, + }); + } + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.dataAdministration, [ + { + id: DSM_APP_ID_FOR_STANDARD_APPLICATION, + category: { + id: DSM_APP_ID_FOR_STANDARD_APPLICATION, + label: PLUGIN_NAME, + order: 200, + }, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ + { + id: DSM_APP_ID_FOR_STANDARD_APPLICATION, + category: DEFAULT_APP_CATEGORIES.manage, + order: 100, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [ + { + id: DSM_APP_ID_FOR_STANDARD_APPLICATION, + category: DEFAULT_APP_CATEGORIES.manage, + order: 100, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ + { + id: DSM_APP_ID_FOR_STANDARD_APPLICATION, + category: DEFAULT_APP_CATEGORIES.manage, + order: 100, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.analytics, [ + { + id: DSM_APP_ID_FOR_STANDARD_APPLICATION, + category: DEFAULT_APP_CATEGORIES.manage, + order: 100, + }, + ]); + const registerAuthenticationMethod = (authMethod: AuthenticationMethod) => { if (this.started) { throw new Error( diff --git a/src/plugins/dev_tools/public/dev_tools_icon.tsx b/src/plugins/dev_tools/public/dev_tools_icon.tsx new file mode 100644 index 000000000000..933b7af0037f --- /dev/null +++ b/src/plugins/dev_tools/public/dev_tools_icon.tsx @@ -0,0 +1,18 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiButtonIcon } from '@elastic/eui'; +import { CoreStart } from 'opensearch-dashboards/public'; + +export function DevToolsIcon({ core, appId }: { core: CoreStart; appId: string }) { + return ( + core.application.navigateToApp(appId)} + /> + ); +} diff --git a/src/plugins/dev_tools/public/plugin.ts b/src/plugins/dev_tools/public/plugin.ts index 6bc40adc5d54..6355d769e66d 100644 --- a/src/plugins/dev_tools/public/plugin.ts +++ b/src/plugins/dev_tools/public/plugin.ts @@ -48,6 +48,7 @@ import { CreateDevToolArgs, DevToolApp, createDevToolApp } from './dev_tool'; import './index.scss'; import { ManagementOverViewPluginSetup } from '../../management_overview/public'; import { toMountPoint } from '../../opensearch_dashboards_react/public'; +import { DevToolsIcon } from './dev_tools_icon'; export interface DevToolsSetupDependencies { urlForwarding: UrlForwardingSetup; @@ -135,7 +136,18 @@ export class DevToolsPlugin implements Plugin { } public start(core: CoreStart) { - if (this.getSortedDevTools().length === 0) { + if (core.chrome.navGroup.getNavGroupEnabled()) { + core.chrome.navControls.registerLeftBottom({ + order: 4, + mount: toMountPoint( + React.createElement(DevToolsIcon, { + core, + appId: this.id, + }) + ), + }); + } + if (this.getSortedDevTools().length === 0 || core.chrome.navGroup.getNavGroupEnabled()) { this.appStateUpdater.next(() => ({ navLinkStatus: AppNavLinkStatus.hidden })); } else { // Register right navigation for dev tool only when console and futureNavigation are both enabled. diff --git a/src/plugins/discover/public/plugin.test.ts b/src/plugins/discover/public/plugin.test.ts new file mode 100644 index 000000000000..ead12ffc7d79 --- /dev/null +++ b/src/plugins/discover/public/plugin.test.ts @@ -0,0 +1,35 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { coreMock } from '../../../core/public/mocks'; +import { DiscoverPlugin } from './plugin'; +import { dataPluginMock } from '../../data/public/mocks'; +import { embeddablePluginMock } from '../../embeddable/public/mocks'; +import { opensearchDashboardsLegacyPluginMock } from '../../opensearch_dashboards_legacy/public/mocks'; +import { urlForwardingPluginMock } from '../../url_forwarding/public/mocks'; +import { uiActionsPluginMock } from '../../ui_actions/public/mocks'; +import { visualizationsPluginMock } from '../../visualizations/public/mocks'; + +describe('DiscoverPlugin', () => { + it('setup successfully', () => { + const setupMock = coreMock.createSetup(); + const initializerContext = coreMock.createPluginInitializerContext(); + const pluginInstance = new DiscoverPlugin(initializerContext); + expect(() => + pluginInstance.setup(setupMock, { + data: dataPluginMock.createSetupContract(), + embeddable: embeddablePluginMock.createSetupContract(), + opensearchDashboardsLegacy: opensearchDashboardsLegacyPluginMock.createSetupContract(), + urlForwarding: urlForwardingPluginMock.createSetupContract(), + uiActions: uiActionsPluginMock.createSetupContract(), + visualizations: visualizationsPluginMock.createSetupContract(), + dataExplorer: { + registerView: jest.fn(), + }, + }) + ).not.toThrow(); + expect(setupMock.chrome.navGroup.addNavLinksToGroup).toBeCalledTimes(5); + }); +}); diff --git a/src/plugins/discover/public/plugin.ts b/src/plugins/discover/public/plugin.ts index 8b46889a8e36..8ac4ca23ba9b 100644 --- a/src/plugins/discover/public/plugin.ts +++ b/src/plugins/discover/public/plugin.ts @@ -33,7 +33,7 @@ import { lazy } from 'react'; import { DataPublicPluginStart, DataPublicPluginSetup, opensearchFilters } from '../../data/public'; import { SavedObjectLoader } from '../../saved_objects/public'; import { url } from '../../opensearch_dashboards_utils/public'; -import { DEFAULT_APP_CATEGORIES } from '../../../core/public'; +import { DEFAULT_APP_CATEGORIES, DEFAULT_NAV_GROUPS } from '../../../core/public'; import { UrlGeneratorState } from '../../share/public'; import { DocViewInput, DocViewInputFn } from './application/doc_views/doc_views_types'; import { generateDocViewsUrl } from './application/components/doc_views/generate_doc_views_url'; @@ -291,6 +291,46 @@ export class DiscoverPlugin }, }); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ + { + id: PLUGIN_ID, + category: undefined, + order: 300, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ + { + id: PLUGIN_ID, + category: undefined, + order: 300, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.analytics, [ + { + id: PLUGIN_ID, + category: undefined, + order: 200, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [ + { + id: PLUGIN_ID, + category: undefined, + order: 200, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ + { + id: PLUGIN_ID, + category: undefined, + order: 200, + }, + ]); + plugins.urlForwarding.forwardApp('doc', 'discover', (path) => { return `#${path}`; }); diff --git a/src/plugins/home/public/mocks/index.ts b/src/plugins/home/public/mocks/index.ts index da84d42dd5ca..84927b73dd49 100644 --- a/src/plugins/home/public/mocks/index.ts +++ b/src/plugins/home/public/mocks/index.ts @@ -32,12 +32,14 @@ import { featureCatalogueRegistryMock } from '../services/feature_catalogue/feat import { environmentServiceMock } from '../services/environment/environment.mock'; import { configSchema } from '../../config'; import { tutorialServiceMock } from '../services/tutorials/tutorial_service.mock'; +import { sectionTypeMock } from '../plugin.test.mocks'; const createSetupContract = () => ({ featureCatalogue: featureCatalogueRegistryMock.createSetup(), environment: environmentServiceMock.createSetup(), tutorials: tutorialServiceMock.createSetup(), config: configSchema.validate({}), + sectionTypes: sectionTypeMock.setup(), }); export const homePluginMock = { diff --git a/src/plugins/home/public/plugin.test.mocks.ts b/src/plugins/home/public/plugin.test.mocks.ts index 67d30bcf714a..5b37c2896d59 100644 --- a/src/plugins/home/public/plugin.test.mocks.ts +++ b/src/plugins/home/public/plugin.test.mocks.ts @@ -32,6 +32,7 @@ import { featureCatalogueRegistryMock } from './services/feature_catalogue/featu import { environmentServiceMock } from './services/environment/environment.mock'; import { tutorialServiceMock } from './services/tutorials/tutorial_service.mock'; import { sectionTypeServiceMock } from './services/section_type/section_type.mock'; +import { FeatureCatalogueCategory } from './services/feature_catalogue'; export const registryMock = featureCatalogueRegistryMock.create(); export const environmentMock = environmentServiceMock.create(); @@ -42,4 +43,5 @@ jest.doMock('./services', () => ({ EnvironmentService: jest.fn(() => environmentMock), TutorialService: jest.fn(() => tutorialMock), SectionTypeService: jest.fn(() => sectionTypeMock), + FeatureCatalogueCategory, })); diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index a9e4cb263e88..3256963d6c0a 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -64,6 +64,7 @@ import { PLUGIN_ID, HOME_APP_BASE_PATH, IMPORT_SAMPLE_DATA_APP_ID } from '../com import { DataSourcePluginStart } from '../../data_source/public'; import { workWithDataSection } from './application/components/homepage/sections/work_with_data'; import { learnBasicsSection } from './application/components/homepage/sections/learn_basics'; +import { DEFAULT_NAV_GROUPS } from '../../../core/public'; export interface HomePluginStartDependencies { data: DataPublicPluginStart; @@ -135,7 +136,9 @@ export class HomePublicPlugin core.application.register({ id: PLUGIN_ID, title: 'Home', - navLinkStatus: AppNavLinkStatus.hidden, + navLinkStatus: core.chrome.navGroup.getNavGroupEnabled() + ? undefined + : AppNavLinkStatus.hidden, mount: async (params: AppMountParameters) => { const [coreStart] = await core.getStartServices(); setCommonService(); @@ -148,6 +151,13 @@ export class HomePublicPlugin workspaceAvailability: WorkspaceAvailability.outsideWorkspace, }); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ + { + id: PLUGIN_ID, + title: 'Home', + }, + ]); + // Register import sample data as a standalone app so that it is available inside workspace. core.application.register({ id: IMPORT_SAMPLE_DATA_APP_ID, diff --git a/src/plugins/index_pattern_management/public/management_app/mount_management_section.tsx b/src/plugins/index_pattern_management/public/management_app/mount_management_section.tsx index af37e6ddb719..020fb0ae56a4 100644 --- a/src/plugins/index_pattern_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/index_pattern_management/public/management_app/mount_management_section.tsx @@ -37,6 +37,7 @@ import { I18nProvider } from '@osd/i18n/react'; import { StartServicesAccessor } from 'src/core/public'; import { DataSourcePluginSetup } from 'src/plugins/data_source/public'; +import { EuiPageContent } from '@elastic/eui'; import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; import { ManagementAppMountParams } from '../../../management/public'; import { @@ -60,7 +61,7 @@ const readOnlyBadge = { export async function mountManagementSection( getStartServices: StartServicesAccessor, - params: ManagementAppMountParams, + params: ManagementAppMountParams & { wrapInPage?: boolean }, getMlCardState: () => MlCardState, dataSource?: DataSourcePluginSetup ) { @@ -94,25 +95,35 @@ export async function mountManagementSection( hideLocalCluster, }; + const content = ( + + + + + + + + + + + + + + + + + ); + ReactDOM.render( - - - - - - - - - - - - - - - - + {params.wrapInPage ? ( + + {content} + + ) : ( + content + )} , params.element diff --git a/src/plugins/index_pattern_management/public/plugin.test.ts b/src/plugins/index_pattern_management/public/plugin.test.ts new file mode 100644 index 000000000000..e207af770af3 --- /dev/null +++ b/src/plugins/index_pattern_management/public/plugin.test.ts @@ -0,0 +1,25 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { coreMock } from '../../../core/public/mocks'; +import { IndexPatternManagementPlugin } from './plugin'; +import { urlForwardingPluginMock } from '../../url_forwarding/public/mocks'; +import { managementPluginMock } from '../../management/public/mocks'; + +describe('DiscoverPlugin', () => { + it('setup successfully', () => { + const setupMock = coreMock.createSetup(); + const initializerContext = coreMock.createPluginInitializerContext(); + const pluginInstance = new IndexPatternManagementPlugin(initializerContext); + expect(() => + pluginInstance.setup(setupMock, { + urlForwarding: urlForwardingPluginMock.createSetupContract(), + management: managementPluginMock.createSetupContract(), + }) + ).not.toThrow(); + expect(setupMock.application.register).toBeCalledTimes(1); + expect(setupMock.chrome.navGroup.addNavLinksToGroup).toBeCalledTimes(5); + }); +}); diff --git a/src/plugins/index_pattern_management/public/plugin.ts b/src/plugins/index_pattern_management/public/plugin.ts index 98eaab6160ee..7ee82dbcc3b0 100644 --- a/src/plugins/index_pattern_management/public/plugin.ts +++ b/src/plugins/index_pattern_management/public/plugin.ts @@ -29,7 +29,13 @@ */ import { i18n } from '@osd/i18n'; -import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; +import { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + AppMountParameters, +} from 'src/core/public'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { DataSourcePluginSetup, DataSourcePluginStart } from 'src/plugins/data_source/public'; import { UrlForwardingSetup } from '../../url_forwarding/public'; @@ -40,6 +46,7 @@ import { } from './service'; import { ManagementSetup } from '../../management/public'; +import { DEFAULT_NAV_GROUPS, AppStatus, DEFAULT_APP_CATEGORIES } from '../../../core/public'; export interface IndexPatternManagementSetupDependencies { management: ManagementSetup; @@ -115,6 +122,73 @@ export class IndexPatternManagementPlugin }, }); + core.application.register({ + id: IPM_APP_ID, + title: sectionsHeader, + status: core.chrome.navGroup.getNavGroupEnabled() + ? AppStatus.accessible + : AppStatus.inaccessible, + mount: async (params: AppMountParameters) => { + const { mountManagementSection } = await import('./management_app'); + const [coreStart] = await core.getStartServices(); + + return mountManagementSection( + core.getStartServices, + { + ...params, + basePath: core.http.basePath.get(), + setBreadcrumbs: coreStart.chrome.setBreadcrumbs, + wrapInPage: true, + }, + () => this.indexPatternManagementService.environmentService.getEnvironment().ml(), + dataSource + ); + }, + }); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.analytics, [ + { + id: IPM_APP_ID, + category: DEFAULT_APP_CATEGORIES.manage, + order: 200, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ + { + id: IPM_APP_ID, + category: DEFAULT_APP_CATEGORIES.manage, + order: 200, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [ + { + id: IPM_APP_ID, + category: DEFAULT_APP_CATEGORIES.manage, + order: 200, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ + { + id: IPM_APP_ID, + category: DEFAULT_APP_CATEGORIES.manage, + order: 200, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.dataAdministration, [ + { + id: IPM_APP_ID, + category: { + id: IPM_APP_ID, + label: sectionsHeader, + order: 100, + }, + }, + ]); + return this.indexPatternManagementService.setup({ httpClient: core.http }); } diff --git a/src/plugins/management/public/components/settings_icon.tsx b/src/plugins/management/public/components/settings_icon.tsx new file mode 100644 index 000000000000..7c5de3e2393c --- /dev/null +++ b/src/plugins/management/public/components/settings_icon.tsx @@ -0,0 +1,61 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState, useRef } from 'react'; +import { EuiButtonIcon, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { useObservable } from 'react-use'; +import { Observable } from 'rxjs'; +import { DEFAULT_NAV_GROUPS, NavGroupItemInMap } from '../../../../core/public'; + +export function SettingsIcon({ core }: { core: CoreStart }) { + const [isPopoverOpen, setPopover] = useState(false); + const navGroupsMapRef = useRef>>( + core.chrome.navGroup.getNavGroupsMap$() + ); + const navGroupMap = useObservable(navGroupsMapRef.current, undefined); + const onItemClick = (groupId: string) => { + setPopover(false); + core.chrome.navGroup.setCurrentNavGroup(groupId); + if (navGroupMap) { + const firstNavItem = navGroupMap[groupId]?.navLinks[0]; + if (firstNavItem?.id) { + core.application.navigateToApp(firstNavItem.id); + } + } + }; + const items = [ + onItemClick(DEFAULT_NAV_GROUPS.settingsAndSetup.id)} + > + {DEFAULT_NAV_GROUPS.settingsAndSetup.title} + , + onItemClick(DEFAULT_NAV_GROUPS.dataAdministration.id)} + > + {DEFAULT_NAV_GROUPS.dataAdministration.title} + , + ]; + + return ( + setPopover(true)} + /> + } + isOpen={isPopoverOpen} + closePopover={() => setPopover(false)} + ownFocus={false} + > + + + ); +} diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index 81a970a0fc48..0e4676297a1e 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -28,6 +28,7 @@ * under the License. */ +import React from 'react'; import { i18n } from '@osd/i18n'; import { BehaviorSubject } from 'rxjs'; import { ManagementSetup, ManagementStart } from './types'; @@ -50,6 +51,8 @@ import { getSectionsServiceStartPrivate, } from './management_sections_service'; import { ManagementOverViewPluginSetup } from '../../management_overview/public'; +import { toMountPoint } from '../../opensearch_dashboards_react/public'; +import { SettingsIcon } from './components/settings_icon'; interface ManagementSetupDependencies { home?: HomePublicPluginSetup; @@ -79,6 +82,9 @@ export class ManagementPlugin implements Plugin section.getAppsEnabled().length > 0); - if (!this.hasAnyEnabledApps) { + if (core.chrome.navGroup.getNavGroupEnabled()) { + this.appUpdater.next(() => { + return { + navLinkStatus: AppNavLinkStatus.hidden, + }; + }); + } else if (!this.hasAnyEnabledApps) { this.appUpdater.next(() => { return { status: AppStatus.inaccessible, @@ -121,6 +133,17 @@ export class ManagementPlugin implements Plugin { const { element } = params; const [core] = await getStartServices(); diff --git a/src/plugins/opensearch_dashboards_overview/public/plugin.ts b/src/plugins/opensearch_dashboards_overview/public/plugin.ts index 3af37fc8cfbb..f774acf0651f 100644 --- a/src/plugins/opensearch_dashboards_overview/public/plugin.ts +++ b/src/plugins/opensearch_dashboards_overview/public/plugin.ts @@ -83,7 +83,12 @@ export class OpenSearchDashboardsOverviewPlugin if (!hasOpenSearchDashboardsApp) { return { status: AppStatus.inaccessible, navLinkStatus: AppNavLinkStatus.hidden }; } else { - return { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.default }; + return { + status: AppStatus.accessible, + navLinkStatus: core.chrome.navGroup.getNavGroupEnabled() + ? AppNavLinkStatus.hidden + : AppNavLinkStatus.default, + }; } }; }) diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx index 1c9bf676d5b3..9e5cbc1b00bd 100644 --- a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx +++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx @@ -33,7 +33,7 @@ import ReactDOM from 'react-dom'; import { Router, Switch, Route } from 'react-router-dom'; import { I18nProvider } from '@osd/i18n/react'; import { i18n } from '@osd/i18n'; -import { EuiLoadingSpinner } from '@elastic/eui'; +import { EuiLoadingSpinner, EuiPageContent } from '@elastic/eui'; import { CoreSetup } from 'src/core/public'; import { DataSourceManagementPluginSetup } from 'src/plugins/data_source_management/public'; import { ManagementAppMountParams } from '../../../management/public'; @@ -44,7 +44,7 @@ import { getAllowedTypes } from './../lib'; interface MountParams { core: CoreSetup; serviceRegistry: ISavedObjectsManagementServiceRegistry; - mountParams: ManagementAppMountParams; + mountParams: ManagementAppMountParams & { wrapInPage?: boolean }; dataSourceEnabled: boolean; dataSourceManagement?: DataSourceManagementPluginSetup; } @@ -84,43 +84,53 @@ export const mountManagementSection = async ({ return children! as React.ReactElement; }; + const content = ( + + + + + }> + + + + + + + }> + + + + + + + ); + ReactDOM.render( - - - - - }> - - - - - - - }> - - - - - - + {mountParams.wrapInPage ? ( + + {content} + + ) : ( + content + )} , element ); diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index 831daa0df443..bbf9fcbe141e 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -29,7 +29,7 @@ */ import { i18n } from '@osd/i18n'; -import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; +import { AppMountParameters, CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { DataSourcePluginSetup } from 'src/plugins/data_source/public'; import { DataSourceManagementPluginSetup } from 'src/plugins/data_source_management/public'; @@ -61,6 +61,7 @@ import { } from './services'; import { registerServices } from './register_services'; import { bootstrap } from './ui_actions_bootstrap'; +import { DEFAULT_NAV_GROUPS, DEFAULT_APP_CATEGORIES } from '../../../core/public'; export interface SavedObjectsManagementPluginSetup { actions: SavedObjectsManagementActionServiceSetup; @@ -151,6 +152,71 @@ export class SavedObjectsManagementPlugin }, }); + if (core.chrome.navGroup.getNavGroupEnabled()) { + core.application.register({ + id: 'objects', + title: i18n.translate('savedObjectsManagement.assets.label', { + defaultMessage: 'Assets', + }), + mount: async (params: AppMountParameters) => { + const { mountManagementSection } = await import('./management_section'); + const [coreStart] = await core.getStartServices(); + + return mountManagementSection({ + core, + serviceRegistry: this.serviceRegistry, + mountParams: { + ...params, + basePath: core.http.basePath.get(), + setBreadcrumbs: coreStart.chrome.setBreadcrumbs, + wrapInPage: true, + }, + dataSourceEnabled: !!dataSource, + dataSourceManagement, + }); + }, + }); + } + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [ + { + id: 'objects', + order: 300, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ + { + id: 'objects', + category: DEFAULT_APP_CATEGORIES.manage, + order: 300, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [ + { + id: 'objects', + category: DEFAULT_APP_CATEGORIES.manage, + order: 300, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ + { + id: 'objects', + category: DEFAULT_APP_CATEGORIES.manage, + order: 300, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.analytics, [ + { + id: 'objects', + category: DEFAULT_APP_CATEGORIES.manage, + order: 300, + }, + ]); + // sets up the context mappings and registers any triggers/actions for the plugin bootstrap(uiActions); diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index c146efef1fab..3a2ffc133747 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -71,6 +71,7 @@ import { } from './services'; import { visualizeFieldAction } from './actions/visualize_field_action'; import { createVisualizeUrlGenerator } from './url_generator'; +import { DEFAULT_NAV_GROUPS } from '../../../core/public'; export interface VisualizePluginStartDependencies { data: DataPublicPluginStart; @@ -150,8 +151,10 @@ export class VisualizePlugin setUISettings(core.uiSettings); uiActions.addTriggerAction(VISUALIZE_FIELD_TRIGGER, visualizeFieldAction); + const visualizeAppId = 'visualize'; + core.application.register({ - id: 'visualize', + id: visualizeAppId, title: 'Visualize', order: 8000, euiIconType: 'inputOutput', @@ -225,6 +228,35 @@ export class VisualizePlugin }, }); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ + { + id: visualizeAppId, + category: DEFAULT_APP_CATEGORIES.dashboardAndReport, + order: 200, + }, + ]); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ + { + id: visualizeAppId, + category: DEFAULT_APP_CATEGORIES.dashboardAndReport, + order: 200, + }, + ]); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.analytics, [ + { + id: visualizeAppId, + category: DEFAULT_APP_CATEGORIES.dashboardAndReport, + order: 200, + }, + ]); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [ + { + id: visualizeAppId, + category: DEFAULT_APP_CATEGORIES.analyzeSearch, + order: 400, + }, + ]); + urlForwarding.forwardApp('visualize', 'visualize'); if (home) { diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index a8fb32121ea8..ad1f6f5996c6 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -335,6 +335,19 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> */ savedObjectsManagement?.columns.register(getWorkspaceColumn(core)); + /** + * Add workspace list to settings and setup group + */ + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [ + { + id: WORKSPACE_LIST_APP_ID, + order: 150, + title: i18n.translate('workspace.settings.workspaceSettings', { + defaultMessage: 'Workspace settings', + }), + }, + ]); + return {}; } From 1b8c801d7c5c9eb6ac2ea242943d3f95285024ce Mon Sep 17 00:00:00 2001 From: yuboluo Date: Thu, 18 Jul 2024 22:05:33 +0800 Subject: [PATCH 077/276] [Manual Backport][2.x][Data Source] Restrict to manage data source on the DSM UI (#7303) * Restrict to manage data source on the DSM UI Signed-off-by: yubonluo * fix unit test error Signed-off-by: yubonluo --------- Signed-off-by: yubonluo --- changelogs/fragments/7214.yml | 2 + config/opensearch_dashboards.yml | 6 + .../data_source/common/data_sources/types.ts | 6 + src/plugins/data_source/config.ts | 4 + src/plugins/data_source/server/plugin.ts | 21 + .../data_source_table.test.tsx.snap | 2287 +++++++++++++++++ .../data_source_table.test.tsx | 37 +- .../data_source_table/data_source_table.tsx | 8 +- .../edit_form/edit_data_source_form.test.tsx | 5 + .../edit_form/edit_data_source_form.tsx | 40 +- .../components/header/header.test.tsx | 35 + .../components/header/header.tsx | 10 +- .../edit_data_source.test.tsx | 5 +- .../edit_data_source/edit_data_source.tsx | 2 + .../management_section/mount_section.tsx | 5 + 15 files changed, 2448 insertions(+), 25 deletions(-) create mode 100644 changelogs/fragments/7214.yml diff --git a/changelogs/fragments/7214.yml b/changelogs/fragments/7214.yml new file mode 100644 index 000000000000..7369e06aa40a --- /dev/null +++ b/changelogs/fragments/7214.yml @@ -0,0 +1,2 @@ +feat: +- [DataSource] Restrict to edit data source on the DSM UI. ([#7214](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7214)) \ No newline at end of file diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index 95484e787e41..dd41817ff88c 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -321,6 +321,12 @@ # AWSSigV4: # enabled: true +# Optional setting that controls the permissions of data source to create, update and delete. +# "none": The data source is readonly for all users. +# "dashboard_admin": The data source can only be managed by dashboard admin. +# "all": The data source can be managed by all users. Default to "all". +# data_source.manageableBy: "all" + # Set the value of this setting to false to hide the help menu link to the OpenSearch Dashboards user survey # opensearchDashboards.survey.url: "https://survey.opensearch.org" diff --git a/src/plugins/data_source/common/data_sources/types.ts b/src/plugins/data_source/common/data_sources/types.ts index cde21f648c61..bd147ac00c04 100644 --- a/src/plugins/data_source/common/data_sources/types.ts +++ b/src/plugins/data_source/common/data_sources/types.ts @@ -60,3 +60,9 @@ export enum DataSourceEngineType { Elasticsearch = 'Elasticsearch', NA = 'No Engine Type Available', } + +export enum ManageableBy { + All = 'all', + DashboardAdmin = 'dashboard_admin', + None = 'none', +} diff --git a/src/plugins/data_source/config.ts b/src/plugins/data_source/config.ts index 30824b486257..36c298cde119 100644 --- a/src/plugins/data_source/config.ts +++ b/src/plugins/data_source/config.ts @@ -59,6 +59,10 @@ export const configSchema = schema.object({ enabled: schema.boolean({ defaultValue: true }), }), }), + manageableBy: schema.oneOf( + [schema.literal('all'), schema.literal('dashboard_admin'), schema.literal('none')], + { defaultValue: 'all' } + ), }); export type DataSourcePluginConfigType = TypeOf; diff --git a/src/plugins/data_source/server/plugin.ts b/src/plugins/data_source/server/plugin.ts index bbf5a89d1b53..fa3085a63935 100644 --- a/src/plugins/data_source/server/plugin.ts +++ b/src/plugins/data_source/server/plugin.ts @@ -33,6 +33,8 @@ import { registerTestConnectionRoute } from './routes/test_connection'; import { registerFetchDataSourceMetaDataRoute } from './routes/fetch_data_source_metadata'; import { AuthenticationMethodRegistry, IAuthenticationMethodRegistry } from './auth_registry'; import { CustomApiSchemaRegistry } from './schema_registry'; +import { ManageableBy } from '../common/data_sources'; +import { getWorkspaceState } from '../../../../src/core/server/utils'; export class DataSourcePlugin implements Plugin { private readonly logger: Logger; @@ -81,6 +83,25 @@ export class DataSourcePlugin implements Plugin ({ + dataSource: { + canManage: false, + }, + })); + + core.capabilities.registerSwitcher((request) => { + const { requestWorkspaceId, isDashboardAdmin } = getWorkspaceState(request); + // User can not manage data source in the workspace. + const canManage = + (manageableBy === ManageableBy.All && !requestWorkspaceId) || + (manageableBy === ManageableBy.DashboardAdmin && + isDashboardAdmin !== false && + !requestWorkspaceId); + + return { dataSource: { canManage } }; + }); + core.logging.configure( this.config$.pipe( map((dataSourceConfig) => ({ diff --git a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap index acab011f27a8..05fd70496974 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap @@ -2532,3 +2532,2290 @@ exports[`DataSourceTable should get datasources successful should render normall `; + +exports[`DataSourceTable should not manage datasources when canManageDataSource is false should render empty table 1`] = ` + + + + +
+ +
+ +
+ +

+ + + Data Sources + + +

+
+ +
+ + +
+

+ + + Create and manage data source connections to help you retrieve data from multiple OpenSearch compatible sources. + + +

+
+
+
+ + +
+ + + + + + + +
+
+
+ + +
+ + +
+ + +
+ +
+ + + No Data Source Connections have been created yet. + + +
+
+ +
+ +
+ + +
+ +
+ + + + +`; diff --git a/src/plugins/data_source_management/public/components/data_source_table/data_source_table.test.tsx b/src/plugins/data_source_management/public/components/data_source_table/data_source_table.test.tsx index b0cb56bdac62..acb4d5d7d853 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/data_source_table.test.tsx +++ b/src/plugins/data_source_management/public/components/data_source_table/data_source_table.test.tsx @@ -24,7 +24,10 @@ const tableColumnHeaderButtonIdentifier = 'EuiTableHeaderCell .euiTableHeaderBut const emptyStateIdentifier = '[data-test-subj="datasourceTableEmptyState"]'; describe('DataSourceTable', () => { - const mockedContext = mockManagementPlugin.createDataSourceManagementContext(); + const mockedContext = { + ...mockManagementPlugin.createDataSourceManagementContext(), + application: { capabilities: { dataSource: { canManage: true } } }, + }; const uiSettings = mockedContext.uiSettings; let component: ReactWrapper, React.Component<{}, {}, any>>; const history = (scopedHistoryMock.create() as unknown) as ScopedHistory; @@ -169,4 +172,36 @@ describe('DataSourceTable', () => { expect(component.find(confirmModalIdentifier).exists()).toBe(false); }); }); + + describe('should not manage datasources when canManageDataSource is false', () => { + const mockedContextWithFalseManage = { + ...mockManagementPlugin.createDataSourceManagementContext(), + application: { capabilities: { dataSource: { canManage: false } } }, + }; + beforeEach(async () => { + spyOn(utils, 'getDataSources').and.returnValue(Promise.reject()); + await act(async () => { + component = await mount( + wrapWithIntl( + + ), + { + wrappingComponent: OpenSearchDashboardsContextProvider, + wrappingComponentProps: { + services: mockedContextWithFalseManage, + }, + } + ); + }); + component.update(); + }); + test('should render empty table', () => { + expect(component).toMatchSnapshot(); + expect(component.find(emptyStateIdentifier).exists()).toBe(true); + }); + }); }); diff --git a/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx b/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx index 718f83e5e977..0f1abb2d755b 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx +++ b/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx @@ -57,6 +57,7 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { savedObjects, notifications: { toasts }, uiSettings, + application, } = useOpenSearchDashboards().services; /* Component state variables */ @@ -65,6 +66,7 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { const [isLoading, setIsLoading] = React.useState(false); const [isDeleting, setIsDeleting] = React.useState(false); const [confirmDeleteVisible, setConfirmDeleteVisible] = React.useState(false); + const canManageDataSource = !!application.capabilities?.dataSource?.canManage; /* useEffectOnce hook to avoid these methods called multiple times when state is updated. */ useEffectOnce(() => { @@ -118,11 +120,11 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { }; const renderToolsRight = () => { - return ( + return canManageDataSource ? ( {renderDeleteButton()} - ); + ) : null; }; const search = { @@ -372,7 +374,7 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { } - {createButtonEmptyState} + {canManageDataSource ? createButtonEmptyState : null} diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.test.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.test.tsx index 876e36bf56ff..73357cafa62e 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.test.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/edit_form/edit_data_source_form.test.tsx @@ -90,6 +90,7 @@ describe('Datasource Management: Edit Datasource Form', () => { onSetDefaultDataSource={mockFn} handleTestConnection={mockFn} displayToastMessage={mockFn} + canManageDataSource={true} /> ), { @@ -261,6 +262,7 @@ describe('Datasource Management: Edit Datasource Form', () => { handleSubmit={mockFn} handleTestConnection={mockFn} displayToastMessage={mockFn} + canManageDataSource={true} /> ), { @@ -373,6 +375,7 @@ describe('Datasource Management: Edit Datasource Form', () => { onSetDefaultDataSource={mockFn} handleTestConnection={mockFn} displayToastMessage={mockFn} + canManageDataSource={true} /> ), { @@ -593,6 +596,7 @@ describe('With Registered Authentication', () => { onSetDefaultDataSource={jest.fn()} handleTestConnection={jest.fn()} displayToastMessage={jest.fn()} + canManageDataSource={true} /> ), { @@ -634,6 +638,7 @@ describe('With Registered Authentication', () => { onSetDefaultDataSource={jest.fn()} handleTestConnection={jest.fn()} displayToastMessage={jest.fn()} + canManageDataSource={true} /> ), { 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 e227e5e2087c..74ec7362381a 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 @@ -56,6 +56,7 @@ export interface EditDataSourceProps { onDeleteDataSource?: () => Promise; onSetDefaultDataSource: () => Promise; displayToastMessage: (info: ToastMessageItem) => void; + canManageDataSource: boolean; } export interface EditDataSourceState { formErrorsByField: CreateEditDataSourceValidation; @@ -644,6 +645,7 @@ export class EditDataSourceForm extends React.Component ); }; @@ -1119,24 +1121,26 @@ export class EditDataSourceForm extends React.Component - - - - - + {this.props.canManageDataSource ? ( + + + + + + ) : null} ); diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.test.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.test.tsx index 5a23b72881a1..4953e21647c7 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.test.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.test.tsx @@ -34,6 +34,7 @@ describe('Datasource Management: Edit Datasource Header', () => { dataSourceName={dataSourceName} onClickSetDefault={mockFn} isDefault={false} + canManageDataSource={true} /> ), { @@ -87,6 +88,7 @@ describe('Datasource Management: Edit Datasource Header', () => { dataSourceName={dataSourceName} onClickSetDefault={mockFn} isDefault={false} + canManageDataSource={true} /> ), { @@ -116,6 +118,7 @@ describe('Datasource Management: Edit Datasource Header', () => { dataSourceName={dataSourceName} onClickSetDefault={onClickSetDefault} isDefault={isDefaultDataSourceState} + canManageDataSource={true} /> ), { @@ -152,6 +155,7 @@ describe('Datasource Management: Edit Datasource Header', () => { dataSourceName={dataSourceName} onClickSetDefault={onClickSetDefault} isDefault={isDefaultDataSourceState} + canManageDataSource={true} /> ), { @@ -174,4 +178,35 @@ describe('Datasource Management: Edit Datasource Header', () => { ); }); }); + describe('should not manage data source', () => { + beforeEach(() => { + component = mount( + wrapWithIntl( +
+ ), + { + wrappingComponent: OpenSearchDashboardsContextProvider, + wrappingComponentProps: { + services: mockedContext, + }, + } + ); + }); + test('should not show delete', () => { + expect(component.find(headerTitleIdentifier).last().text()).toBe(dataSourceName); + expect(component.find(deleteIconIdentifier).exists()).toBe(false); + }); + test('should not show default icon', () => { + expect(component.find(setDefaultButtonIdentifier).exists()).toBe(false); + }); + }); }); diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.tsx index 264647882574..dece5cb78b2b 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.tsx @@ -29,6 +29,7 @@ export const Header = ({ onClickSetDefault, dataSourceName, isDefault, + canManageDataSource, }: { showDeleteIcon: boolean; isFormValid: boolean; @@ -37,6 +38,7 @@ export const Header = ({ onClickSetDefault: () => void; dataSourceName: string; isDefault: boolean; + canManageDataSource: boolean; }) => { /* State Variables */ const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); @@ -175,11 +177,15 @@ export const Header = ({ {/* Test default button */} - {renderDefaultIcon()} + {canManageDataSource ? ( + {renderDefaultIcon()} + ) : null} {/* Test connection button */} {renderTestConnectionButton()} {/* Delete icon button */} - {showDeleteIcon ? renderDeleteButton() : null} + {canManageDataSource ? ( + {showDeleteIcon ? renderDeleteButton() : null} + ) : null} diff --git a/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.test.tsx b/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.test.tsx index d8d175a920d9..f53744d67716 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.test.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.test.tsx @@ -28,7 +28,10 @@ const formIdentifier = 'EditDataSourceForm'; const notFoundIdentifier = '[data-test-subj="dataSourceNotFound"]'; describe('Datasource Management: Edit Datasource Wizard', () => { - const mockedContext = mockManagementPlugin.createDataSourceManagementContext(); + const mockedContext = { + ...mockManagementPlugin.createDataSourceManagementContext(), + application: { capabilities: { dataSource: { canManage: true } } }, + }; const uiSettings = mockedContext.uiSettings; mockedContext.authenticationMethodRegistry.registerAuthenticationMethod( noAuthCredentialAuthMethod diff --git a/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.tsx b/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.tsx index 334a34322ec2..fbf63aaecb0d 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.tsx @@ -46,6 +46,7 @@ export const EditDataSource: React.FunctionComponent().services; const dataSourceID: string = props.match.params.id; @@ -162,6 +163,7 @@ export const EditDataSource: React.FunctionComponent ) : null} {isLoading || !dataSource?.endpoint ? : null} diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx index 9e5cbc1b00bd..0c98f365b39d 100644 --- a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx +++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx @@ -69,6 +69,11 @@ export const mountManagementSection = async ({ if (allowedObjectTypes === undefined) { allowedObjectTypes = await getAllowedTypes(coreStart.http); } + // Restrict user to manage data source in the saved object management page according the manageableBy flag. + const showDataSource = !!coreStart.application.capabilities?.dataSource?.canManage; + allowedObjectTypes = showDataSource + ? allowedObjectTypes + : allowedObjectTypes.filter((type) => type !== 'data-source'); coreStart.chrome.docTitle.change(title); From 747b358e67917ae10408f67bf3d40fe1fb45af5a Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 11:05:41 -0700 Subject: [PATCH 078/276] Condence context menus (#7057) (#7286) * Condense share context menu * Condense console editor actions context menu * Condense filter bar context menus * Condense discover table options context menu * Condense new panel creation context menus * Condense index pattern creation button's menu * Condense index pattern creation wizard's pagination context menu * Condense inspect flyout's view selection context menu * Condense inspect flyout's download options context menu * Condense inspect flyout's request selection context menu * Condense panel-adding flyout's filter menus * Condense group adding context menu in visualization editor --------- (cherry picked from commit f1be0d634643717594e8e5ccefb1c614cb520eec) Signed-off-by: Miki Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../application/components/console_menu.tsx | 2 +- .../data/public/ui/filter_bar/filter_item.tsx | 2 +- .../public/ui/filter_bar/filter_options.tsx | 4 +-- .../view_components/canvas/index.tsx | 1 + .../saved_object_finder_create_new.tsx | 2 +- .../create_button/create_button.tsx | 3 ++- .../components/indices_list/indices_list.tsx | 2 +- .../public/ui/inspector_view_chooser.tsx | 2 +- .../data/components/download_options.tsx | 2 +- .../requests/components/request_selector.tsx | 1 + .../public/finder/saved_object_finder.tsx | 2 ++ .../public/components/share_context_menu.tsx | 1 + .../public/components/url_panel_content.tsx | 25 +++++++++++-------- .../public/components/agg_add.tsx | 3 ++- 14 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/plugins/console/public/application/components/console_menu.tsx b/src/plugins/console/public/application/components/console_menu.tsx index c3015dc7ffa2..f7840247f51b 100644 --- a/src/plugins/console/public/application/components/console_menu.tsx +++ b/src/plugins/console/public/application/components/console_menu.tsx @@ -183,7 +183,7 @@ export class ConsoleMenu extends Component { panelPaddingSize="none" anchorPosition="downLeft" > - + ); diff --git a/src/plugins/data/public/ui/filter_bar/filter_item.tsx b/src/plugins/data/public/ui/filter_bar/filter_item.tsx index 15e6523f3532..bf6e0c341907 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_item.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_item.tsx @@ -361,7 +361,7 @@ export function FilterItem(props: Props) { anchorPosition="downLeft" panelPaddingSize="none" > - + ); } diff --git a/src/plugins/data/public/ui/filter_bar/filter_options.tsx b/src/plugins/data/public/ui/filter_bar/filter_options.tsx index 0865f09864dd..2ffe925b89f7 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_options.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_options.tsx @@ -179,13 +179,13 @@ class FilterOptionsUI extends Component { panelPaddingSize="none" repositionOnScroll > - + - + ); } diff --git a/src/plugins/discover/public/application/view_components/canvas/index.tsx b/src/plugins/discover/public/application/view_components/canvas/index.tsx index 52ebc635e4af..9511448f025a 100644 --- a/src/plugins/discover/public/application/view_components/canvas/index.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/index.tsx @@ -129,6 +129,7 @@ export default function DiscoverCanvas({ setHeaderActionMenu, history }: ViewPro > - + ); } diff --git a/src/plugins/index_pattern_management/public/components/create_button/create_button.tsx b/src/plugins/index_pattern_management/public/components/create_button/create_button.tsx index 84671d44a777..a9e16ef51255 100644 --- a/src/plugins/index_pattern_management/public/components/create_button/create_button.tsx +++ b/src/plugins/index_pattern_management/public/components/create_button/create_button.tsx @@ -107,6 +107,7 @@ export class CreateButton extends Component { anchorPosition="downLeft" > { return ( { onClick={option.onClick} data-test-subj={option.testSubj} > - + {option.text} {option.isBeta ? {this.renderBetaBadge()} : null} diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/indices_list.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/indices_list.tsx index e06bb0a70d3d..d51d94af6346 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/indices_list.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/indices_list.tsx @@ -156,7 +156,7 @@ export class IndicesList extends React.Component - + {paginationControls} diff --git a/src/plugins/inspector/public/ui/inspector_view_chooser.tsx b/src/plugins/inspector/public/ui/inspector_view_chooser.tsx index 230066cea91e..2f6bf71a5ada 100644 --- a/src/plugins/inspector/public/ui/inspector_view_chooser.tsx +++ b/src/plugins/inspector/public/ui/inspector_view_chooser.tsx @@ -140,7 +140,7 @@ export class InspectorViewChooser extends Component { anchorPosition="downRight" repositionOnScroll > - + ); } diff --git a/src/plugins/inspector/public/views/data/components/download_options.tsx b/src/plugins/inspector/public/views/data/components/download_options.tsx index ee0d45fe1af0..558b7ed4b4d3 100644 --- a/src/plugins/inspector/public/views/data/components/download_options.tsx +++ b/src/plugins/inspector/public/views/data/components/download_options.tsx @@ -167,7 +167,7 @@ class DataDownloadOptions extends Component - + ); } diff --git a/src/plugins/inspector/public/views/requests/components/request_selector.tsx b/src/plugins/inspector/public/views/requests/components/request_selector.tsx index f3543ad5b6a4..7a0bb122e6c9 100644 --- a/src/plugins/inspector/public/views/requests/components/request_selector.tsx +++ b/src/plugins/inspector/public/views/requests/components/request_selector.tsx @@ -145,6 +145,7 @@ export class RequestSelector extends Component ); diff --git a/src/plugins/saved_objects/public/finder/saved_object_finder.tsx b/src/plugins/saved_objects/public/finder/saved_object_finder.tsx index ed464399be4a..3d99b4e28e22 100644 --- a/src/plugins/saved_objects/public/finder/saved_object_finder.tsx +++ b/src/plugins/saved_objects/public/finder/saved_object_finder.tsx @@ -425,6 +425,7 @@ class SavedObjectFinderUi extends React.Component< {this.props.showFilter && ( @@ -456,6 +457,7 @@ class SavedObjectFinderUi extends React.Component< > ( { initialPanelId={initialPanelId} panels={panels} data-test-subj="shareContextMenu" + size="s" /> ); diff --git a/src/plugins/share/public/components/url_panel_content.tsx b/src/plugins/share/public/components/url_panel_content.tsx index 1d8069c86ae9..e1d1b4270615 100644 --- a/src/plugins/share/public/components/url_panel_content.tsx +++ b/src/plugins/share/public/components/url_panel_content.tsx @@ -38,6 +38,7 @@ import { EuiFlexItem, EuiForm, EuiFormRow, + EuiText, EuiIconTip, EuiLoadingSpinner, EuiRadioGroup, @@ -135,17 +136,19 @@ export class UrlPanelContent extends Component { data-test-subj="copyShareUrlButton" size="s" > - {this.props.isEmbedded ? ( - - ) : ( - - )} + + {this.props.isEmbedded ? ( + + ) : ( + + )} + )} diff --git a/src/plugins/vis_default_editor/public/components/agg_add.tsx b/src/plugins/vis_default_editor/public/components/agg_add.tsx index f77a48a24999..b0e187d727de 100644 --- a/src/plugins/vis_default_editor/public/components/agg_add.tsx +++ b/src/plugins/vis_default_editor/public/components/agg_add.tsx @@ -99,7 +99,7 @@ function DefaultEditorAggAdd({ repositionOnScroll={true} closePopover={() => setIsPopoverOpen(false)} > - + {(groupName !== AggGroupNames.Buckets || !stats.count) && ( ( Date: Thu, 18 Jul 2024 18:05:42 -0700 Subject: [PATCH 079/276] Disable input in edit data source when data_source.manageableBy is none (#7307) (#7310) * Disable input in edit data source when data_source.manageableBy is none * Changeset file for PR #7307 created/updated * Removed unnecessary canManageDataSource check * Fix lint issue * Update snapshot --------- (cherry picked from commit ddc26fc9eab6e6220a4375c65fdc84163d7c002a) Signed-off-by: Eemi Juntunen Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7307.yml | 2 ++ .../edit_form/edit_data_source_form.tsx | 16 ++++++++++++++-- .../update_aws_credential_modal.test.tsx | 1 + .../update_aws_credential_modal.tsx | 4 ++++ .../update_password_modal.test.tsx.snap | 11 +++++++++++ .../update_password_modal.test.tsx | 1 + .../update_password_modal.tsx | 4 ++++ 7 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/7307.yml diff --git a/changelogs/fragments/7307.yml b/changelogs/fragments/7307.yml new file mode 100644 index 000000000000..ad874b0e9b03 --- /dev/null +++ b/changelogs/fragments/7307.yml @@ -0,0 +1,2 @@ +feat: +- Disable inputs in edit data source screen when data_source.manageableBy is none ([#7307](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7307)) \ No newline at end of file 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 74ec7362381a..64cb56eb2aa5 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 @@ -586,6 +586,7 @@ export class EditDataSourceForm extends React.Component { @@ -601,6 +602,7 @@ export class EditDataSourceForm extends React.Component ) : null} @@ -613,6 +615,7 @@ export class EditDataSourceForm extends React.Component { ) : null} @@ -725,6 +729,7 @@ export class EditDataSourceForm extends React.Component {/* Description */} @@ -745,6 +750,7 @@ export class EditDataSourceForm extends React.Component @@ -837,7 +843,7 @@ export class EditDataSourceForm extends React.Component this.onChangeAuthType(value)} - disabled={this.authOptions.length <= 1} + disabled={this.authOptions.length <= 1 || !this.props.canManageDataSource} name="Credential" data-test-subj="editDataSourceSelectAuthType" /> @@ -883,6 +889,7 @@ export class EditDataSourceForm extends React.Component @@ -895,6 +902,7 @@ export class EditDataSourceForm extends React.Component this.onChangeSigV4ServiceName(value)} name="ServiceName" data-test-subj="editDataSourceFormSigV4ServiceTypeSelect" @@ -989,6 +997,7 @@ export class EditDataSourceForm extends React.Component @@ -1018,7 +1027,10 @@ export class EditDataSourceForm extends React.Component diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/update_aws_credential_modal/update_aws_credential_modal.test.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/update_aws_credential_modal/update_aws_credential_modal.test.tsx index e7c7f0209438..c0cab401a86d 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/update_aws_credential_modal/update_aws_credential_modal.test.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/update_aws_credential_modal/update_aws_credential_modal.test.tsx @@ -20,6 +20,7 @@ describe('UpdateAwsCredentialModal', () => { service: SigV4ServiceName.OpenSearch, handleUpdateAwsCredential: mockHandleUpdateAwsCredential, closeUpdateAwsCredentialModal: mockCloseUpdateAwsCredentialModal, + canManageDataSource: true, }; it('updates new access key state on input change', () => { diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/update_aws_credential_modal/update_aws_credential_modal.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/update_aws_credential_modal/update_aws_credential_modal.tsx index 2fbae293132f..e4ecf0766690 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/update_aws_credential_modal/update_aws_credential_modal.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/update_aws_credential_modal/update_aws_credential_modal.tsx @@ -28,6 +28,7 @@ export interface UpdateAwsCredentialModalProps { service: SigV4ServiceName; handleUpdateAwsCredential: (accessKey: string, secretKey: string) => void; closeUpdateAwsCredentialModal: () => void; + canManageDataSource: boolean; } export const UpdateAwsCredentialModal = ({ @@ -35,6 +36,7 @@ export const UpdateAwsCredentialModal = ({ service, handleUpdateAwsCredential, closeUpdateAwsCredentialModal, + canManageDataSource, }: UpdateAwsCredentialModalProps) => { /* State Variables */ const [newAccessKey, setNewAccessKey] = useState(''); @@ -134,6 +136,7 @@ export const UpdateAwsCredentialModal = ({ spellCheck={false} onChange={(e) => setNewAccessKey(e.target.value)} onBlur={validateNewAccessKey} + disabled={!canManageDataSource} /> @@ -159,6 +162,7 @@ export const UpdateAwsCredentialModal = ({ spellCheck={false} onChange={(e) => setNewSecretKey(e.target.value)} onBlur={validateNewSecretKey} + disabled={!canManageDataSource} /> diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/__snapshots__/update_password_modal.test.tsx.snap b/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/__snapshots__/update_password_modal.test.tsx.snap index 21ec04bd300e..7f8bd04c86a2 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/__snapshots__/update_password_modal.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/update_password_modal/__snapshots__/update_password_modal.test.tsx.snap @@ -5,6 +5,7 @@ exports[`Datasource Management: Update Stored Password Modal should render norma locale="en" > { username={mockUserName} handleUpdatePassword={mockFn} closeUpdatePasswordModal={mockFn} + canManageDataSource={true} /> ), { 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 693a8a84234e..aef52c895a62 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 @@ -25,12 +25,14 @@ export interface UpdatePasswordModalProps { username: string; handleUpdatePassword: (password: string) => void; closeUpdatePasswordModal: () => void; + canManageDataSource: boolean; } export const UpdatePasswordModal = ({ username, handleUpdatePassword, closeUpdatePasswordModal, + canManageDataSource, }: UpdatePasswordModalProps) => { /* State Variables */ const [newPassword, setNewPassword] = useState(''); @@ -128,6 +130,7 @@ export const UpdatePasswordModal = ({ spellCheck={false} onChange={(e) => setNewPassword(e.target.value)} onBlur={validateNewPassword} + disabled={!canManageDataSource} /> {/* Password */} @@ -153,6 +156,7 @@ export const UpdatePasswordModal = ({ spellCheck={false} onChange={(e) => setConfirmNewPassword(e.target.value)} onBlur={validateConfirmNewPassword} + disabled={!canManageDataSource} /> From 8d4af687eae191c7d74e33e9f5f2b74a617fdd70 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:19:48 +0800 Subject: [PATCH 080/276] [Navigation-next] Enable landing page for settings and data administration (#7282) (#7312) * feat: enable landing page for settings and setup * feat: enable landing page for settings and setup * feat: add page header * Changeset file for PR #7236 created/updated * feat: update * feat: add landing page * Changeset file for PR #7282 created/updated * feat: add landing page * feat: optimize code --------- (cherry picked from commit e44bd7e9a3d96d08660554a0cfb14956a49102d5) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: ZilongX <99905560+ZilongX@users.noreply.github.com> --- changelogs/fragments/7282.yml | 2 + src/core/public/chrome/index.ts | 1 + src/core/public/chrome/nav_links/nav_link.ts | 5 + src/core/public/index.ts | 2 + .../__snapshots__/feature_cards.test.tsx.snap | 392 ++++++++++++++++++ .../feature_cards/feature_cards.test.tsx | 119 ++++++ .../feature_cards/feature_cards.tsx | 142 +++++++ .../public/landing_page_application.test.tsx | 22 + .../public/landing_page_application.tsx | 22 + src/plugins/management/public/plugin.ts | 96 +++++ 10 files changed, 803 insertions(+) create mode 100644 changelogs/fragments/7282.yml create mode 100644 src/plugins/management/public/components/feature_cards/__snapshots__/feature_cards.test.tsx.snap create mode 100644 src/plugins/management/public/components/feature_cards/feature_cards.test.tsx create mode 100644 src/plugins/management/public/components/feature_cards/feature_cards.tsx create mode 100644 src/plugins/management/public/landing_page_application.test.tsx create mode 100644 src/plugins/management/public/landing_page_application.tsx diff --git a/changelogs/fragments/7282.yml b/changelogs/fragments/7282.yml new file mode 100644 index 000000000000..c6256ae74bda --- /dev/null +++ b/changelogs/fragments/7282.yml @@ -0,0 +1,2 @@ +feat: +- Enable landing page for settings and data administration ([#7282](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7282)) \ No newline at end of file diff --git a/src/core/public/chrome/index.ts b/src/core/public/chrome/index.ts index 62cc9cb76ec0..f49e0e7efe80 100644 --- a/src/core/public/chrome/index.ts +++ b/src/core/public/chrome/index.ts @@ -51,3 +51,4 @@ export { ChromeNavControl, ChromeNavControls } from './nav_controls'; export { ChromeDocTitle } from './doc_title'; export { RightNavigationOrder } from './constants'; export { ChromeRegistrationNavLink, ChromeNavGroupUpdater, NavGroupItemInMap } from './nav_group'; +export { fulfillRegistrationLinksToChromeNavLinks } from './utils'; diff --git a/src/core/public/chrome/nav_links/nav_link.ts b/src/core/public/chrome/nav_links/nav_link.ts index cddd45234514..21772e2f26ab 100644 --- a/src/core/public/chrome/nav_links/nav_link.ts +++ b/src/core/public/chrome/nav_links/nav_link.ts @@ -102,6 +102,11 @@ export interface ChromeNavLink { * Hides a link from the navigation. */ readonly hidden?: boolean; + + /** + * Description of the nav link + */ + readonly description?: string; } /** @public */ diff --git a/src/core/public/index.ts b/src/core/public/index.ts index dd01046cbc62..59da446d1fe9 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -74,6 +74,7 @@ import { ChromeRegistrationNavLink, ChromeNavGroupUpdater, NavGroupItemInMap, + fulfillRegistrationLinksToChromeNavLinks, } from './chrome'; import { FatalErrorsSetup, FatalErrorsStart, FatalErrorInfo } from './fatal_errors'; import { HttpSetup, HttpStart } from './http'; @@ -375,6 +376,7 @@ export { ChromeRegistrationNavLink, ChromeNavGroupUpdater, NavGroupItemInMap, + fulfillRegistrationLinksToChromeNavLinks, }; export { __osdBootstrap__ } from './osd_bootstrap'; diff --git a/src/plugins/management/public/components/feature_cards/__snapshots__/feature_cards.test.tsx.snap b/src/plugins/management/public/components/feature_cards/__snapshots__/feature_cards.test.tsx.snap new file mode 100644 index 000000000000..d777d7d9e2c0 --- /dev/null +++ b/src/plugins/management/public/components/feature_cards/__snapshots__/feature_cards.test.tsx.snap @@ -0,0 +1,392 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` render with complex navLinks 1`] = ` +
+
+
+
+
+
+
+
+ + + +
+

+ title1 +

+
+
+
+
+
+
+
+ + + +
+

+ title2 +

+
+
+
+
+
+
+
+ + + +
+

+ title3 +

+
+
+
+
+
+
+
+ + + +
+

+ title4 +

+
+
+
+
+
+
+
+
+
+ + + +
+

+ title5 +

+
+
+
+
+
+
+
+
+
+
+
+

+ Dashboard +

+
+
+
+
+
+ + + +
+

+ title1 +

+
+
+
+
+
+
+
+ + + +
+

+ title2 +

+
+
+
+
+
+
+
+ + + +
+

+ title3 +

+
+
+
+
+
+
+
+ + + +
+

+ title4 +

+
+
+
+
+
+
+
+
+
+ + + +
+

+ title5 +

+
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[` render with empty navLinks 1`] = `
`; diff --git a/src/plugins/management/public/components/feature_cards/feature_cards.test.tsx b/src/plugins/management/public/components/feature_cards/feature_cards.test.tsx new file mode 100644 index 000000000000..b4bb4cdc76d8 --- /dev/null +++ b/src/plugins/management/public/components/feature_cards/feature_cards.test.tsx @@ -0,0 +1,119 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import { FeatureCards } from './feature_cards'; +import { AppCategory, ChromeNavLink } from 'opensearch-dashboards/public'; + +const mockCategory: AppCategory = { + id: 'dashboard', + label: 'Dashboard', + order: 2, +}; + +const navLinks: ChromeNavLink[] = [ + { + id: '1', + title: 'title1', + baseUrl: '', + href: '', + }, + { + id: '2', + title: 'title2', + baseUrl: '', + href: '', + }, + { + id: '3', + title: 'title3', + baseUrl: '', + href: '', + }, + { + id: '4', + title: 'title4', + baseUrl: '', + href: '', + }, + { + id: '5', + title: 'title5', + baseUrl: '', + href: '', + }, + { + id: 'category-1', + title: 'title1', + baseUrl: '', + href: '', + category: mockCategory, + }, + { + id: 'category-2', + title: 'title2', + baseUrl: '', + href: '', + category: mockCategory, + }, + { + id: 'category-3', + title: 'title3', + baseUrl: '', + href: '', + category: mockCategory, + }, + { + id: 'category-4', + title: 'title4', + baseUrl: '', + href: '', + category: mockCategory, + }, + { + id: 'category-5', + title: 'title5', + baseUrl: '', + href: '', + category: mockCategory, + }, +]; + +describe('', () => { + it('render with empty navLinks', () => { + const { container } = render( + + ); + expect(container).toMatchSnapshot(); + }); + + it('render with complex navLinks', () => { + const { container, getAllByTestId } = render( + + ); + expect(container).toMatchSnapshot(); + expect(getAllByTestId('landingPageRow_1').length).toEqual(2); + }); + + it('click item', () => { + const mockedNavigateToApp = jest.fn(); + const { getByTestId } = render( + + ); + fireEvent.click(getByTestId('landingPageFeature_1')); + expect(mockedNavigateToApp).toBeCalledWith('1'); + }); +}); diff --git a/src/plugins/management/public/components/feature_cards/feature_cards.tsx b/src/plugins/management/public/components/feature_cards/feature_cards.tsx new file mode 100644 index 000000000000..57d7e128c928 --- /dev/null +++ b/src/plugins/management/public/components/feature_cards/feature_cards.tsx @@ -0,0 +1,142 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { + EuiCard, + EuiFlexGrid, + EuiFlexGroup, + EuiFlexItem, + EuiPageContent, + EuiPageHeader, + EuiPageHeaderSection, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { AppCategory, ChromeNavLink, CoreStart } from 'opensearch-dashboards/public'; +import React, { useMemo } from 'react'; + +export interface FeatureCardsProps { + pageTitle: string; + navLinks: ChromeNavLink[]; + navigateToApp: CoreStart['application']['navigateToApp']; + getStartedCards: Array<{ + id: string; + title: string; + description: string; + }>; +} + +const getStartedTitle = i18n.translate('management.gettingStarted.label', { + defaultMessage: 'Get started', +}); + +export const FeatureCards = ({ + navLinks, + navigateToApp, + pageTitle, + getStartedCards, +}: FeatureCardsProps) => { + const itemsPerRow = 4; + const groupedCardForDisplay = useMemo(() => { + const grouped: Array<{ category?: AppCategory; navLinks: ChromeNavLink[][] }> = []; + // The navLinks has already been sorted based on link / category's order, + // so it is safe to group the links here. + navLinks.forEach((link) => { + let lastGroup = grouped.length ? grouped[grouped.length - 1] : undefined; + if (!lastGroup || lastGroup.category !== link.category) { + lastGroup = { category: link.category, navLinks: [[]] }; + grouped.push(lastGroup); + } + const lastRow = lastGroup.navLinks[lastGroup.navLinks.length - 1]; + if (lastRow.length < itemsPerRow) { + lastRow.push(link); + } else { + lastGroup.navLinks.push([link]); + } + }); + return grouped; + }, [itemsPerRow, navLinks]); + if (!navLinks.length) { + return null; + } + return ( + <> + + + + +

{pageTitle}

+
+
+
+ {getStartedCards.length ? ( + <> + + +

{getStartedTitle}

+
+ + {getStartedCards.map((card) => { + return ( + + + navigateToApp(card.id)} + titleSize="xs" + /> + + + ); + })} + + + ) : null} +
+ + {groupedCardForDisplay.map((group) => ( +
+ {group.category && ( + +

{group.category.label}

+
+ )} + + {group.navLinks.map((row, rowIndex) => { + return ( + + {Array.from({ length: itemsPerRow }).map((item, itemIndexInRow) => { + const link = row[itemIndexInRow]; + const content = link ? ( + navigateToApp(link.id)} + titleSize="xs" + /> + ) : null; + return ( + + {content} + + ); + })} + + ); + })} + +
+ ))} +
+ + ); +}; diff --git a/src/plugins/management/public/landing_page_application.test.tsx b/src/plugins/management/public/landing_page_application.test.tsx new file mode 100644 index 000000000000..13d14ff34609 --- /dev/null +++ b/src/plugins/management/public/landing_page_application.test.tsx @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { renderApp } from './landing_page_application'; + +describe('Landing page application', () => { + it('renders and unmount without crashing', () => { + expect(() => { + const unmountFn = renderApp({ + mountElement: document.createElement('div'), + props: { + navigateToApp: jest.fn(), + navLinks: [], + }, + }); + + unmountFn(); + }).not.toThrow(); + }); +}); diff --git a/src/plugins/management/public/landing_page_application.tsx b/src/plugins/management/public/landing_page_application.tsx new file mode 100644 index 000000000000..f3fd0dbc10aa --- /dev/null +++ b/src/plugins/management/public/landing_page_application.tsx @@ -0,0 +1,22 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; + +import { AppMountParameters } from 'opensearch-dashboards/public'; +import { FeatureCards, FeatureCardsProps } from './components/feature_cards/feature_cards'; + +export const renderApp = ({ + mountElement, + props, +}: { + mountElement: AppMountParameters['element']; + props: FeatureCardsProps; +}) => { + ReactDOM.render(, mountElement); + + return () => ReactDOM.unmountComponentAtNode(mountElement); +}; diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index 0e4676297a1e..8799ad24bce3 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -31,6 +31,7 @@ import React from 'react'; import { i18n } from '@osd/i18n'; import { BehaviorSubject } from 'rxjs'; +import { first } from 'rxjs/operators'; import { ManagementSetup, ManagementStart } from './types'; import { HomePublicPluginSetup } from '../../home/public'; import { @@ -43,6 +44,7 @@ import { AppUpdater, AppStatus, AppNavLinkStatus, + DEFAULT_NAV_GROUPS, } from '../../../core/public'; import { MANAGEMENT_APP_ID } from '../common/contants'; @@ -53,6 +55,7 @@ import { import { ManagementOverViewPluginSetup } from '../../management_overview/public'; import { toMountPoint } from '../../opensearch_dashboards_react/public'; import { SettingsIcon } from './components/settings_icon'; +import { fulfillRegistrationLinksToChromeNavLinks } from '../../../core/public'; interface ManagementSetupDependencies { home?: HomePublicPluginSetup; @@ -97,6 +100,99 @@ export class ManagementPlugin implements Plugin { + const { renderApp } = await import('./landing_page_application'); + const [coreStart] = await core.getStartServices(); + const navGroupMap = await coreStart.chrome.navGroup + .getNavGroupsMap$() + .pipe(first()) + .toPromise(); + const navLinks = navGroupMap[DEFAULT_NAV_GROUPS.settingsAndSetup.id]?.navLinks; + const fulfilledNavLink = fulfillRegistrationLinksToChromeNavLinks( + navLinks || [], + coreStart.chrome.navLinks.getAll() + ).filter((navLink) => navLink.id !== settingsLandingPageId && !navLink.hidden); + + return renderApp({ + mountElement: params.element, + props: { + navigateToApp: coreStart.application.navigateToApp, + navLinks: fulfilledNavLink, + pageTitle: settingsLandingPageTitle, + getStartedCards: [], + }, + }); + }, + }); + + core.application.register({ + id: dataAdministrationLandingPageId, + title: dataAdministrationPageTitle, + order: 100, + navLinkStatus: core.chrome.navGroup.getNavGroupEnabled() + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + mount: async (params: AppMountParameters) => { + const { renderApp } = await import('./landing_page_application'); + const [coreStart] = await core.getStartServices(); + const navGroupMap = await coreStart.chrome.navGroup + .getNavGroupsMap$() + .pipe(first()) + .toPromise(); + const navLinks = navGroupMap[DEFAULT_NAV_GROUPS.dataAdministration.id]?.navLinks; + const fulfilledNavLink = fulfillRegistrationLinksToChromeNavLinks( + navLinks || [], + coreStart.chrome.navLinks.getAll() + ).filter((navLink) => navLink.id !== dataAdministrationLandingPageId && !navLink.hidden); + + return renderApp({ + mountElement: params.element, + props: { + navigateToApp: coreStart.application.navigateToApp, + navLinks: fulfilledNavLink, + pageTitle: dataAdministrationPageTitle, + getStartedCards: [], + }, + }); + }, + }); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [ + { + id: settingsLandingPageId, + order: 0, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.dataAdministration, [ + { + id: dataAdministrationLandingPageId, + order: 0, + }, + ]); + managementOverview?.register({ id: MANAGEMENT_APP_ID, title: this.title, From f699d4363867cef052d8da68bbe3c14f36f0ba55 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 13:37:34 +0800 Subject: [PATCH 081/276] add instruction for force enable new navigation for workspace (#7186) (#7202) (cherry picked from commit 3a32191bc9b148fd501d38a5d652d2d36d93d5ee) Signed-off-by: Hailong Cui Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- config/opensearch_dashboards.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml index dd41817ff88c..bc46a1bdd2b0 100644 --- a/config/opensearch_dashboards.yml +++ b/config/opensearch_dashboards.yml @@ -343,7 +343,11 @@ # Set the value to true to enable workspace feature # Please note, workspace will not work with multi-tenancy. To enable workspace feature, you need to disable multi-tenancy first with `opensearch_security.multitenancy.enabled: false` +# Please uncomment below uiSettings to enable new home/navigation experience when workspace is enabled # workspace.enabled: false +# uiSettings: +# overrides: +# "home:useNewHomePage": true # Optional settings to specify saved object types to be deleted during migration. # This feature can help address compatibility issues that may arise during the migration of saved objects, such as types defined by legacy applications. From 9c6ac88f3ac5eaec8043ca1164caa1268267526c Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 00:04:23 -0700 Subject: [PATCH 082/276] Fixes recently accessed (#7179) (#7313) (cherry picked from commit 89c92efd66363cca472104012adb83e94c81db4b) Signed-off-by: Hailong Cui Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../public/application/view_components/utils/use_search.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index e3a84ae84638..4de9e987bd53 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -82,6 +82,7 @@ export const useSearch = (services: DiscoverViewServices) => { core, toastNotifications, osdUrlStateStorage, + chrome, } = services; const timefilter = data.query.timefilter.timefilter; const fetchStateRef = useRef<{ From acbfcaf87d96f0dcf8d58eba9ecdedd7670491da Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 16:18:34 -0700 Subject: [PATCH 083/276] refactor: density and consistency changes for discover and query bar (#7299) (#7321) * refactor: density and consistency changes for discover and query ba --------- (cherry picked from commit 54cdf2378d3c70192453a092b45ff3de26720355) Signed-off-by: Viraj Sanghvi Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7299.yml | 2 ++ .../public/ui/filter_bar/_global_filter_group.scss | 6 ++---- .../public/ui/filter_bar/_global_filter_item.scss | 2 +- .../data/public/ui/filter_bar/filter_bar.tsx | 4 ++-- .../public/ui/filter_bar/filter_editor/index.tsx | 2 +- .../public/ui/query_string_input/_query_bar.scss | 2 +- .../components/data_grid/data_grid_table_flyout.tsx | 4 +++- .../default_discover_table/_table_cell.scss | 13 +++++++++++-- .../default_discover_table/_table_header.scss | 5 +++++ .../components/default_discover_table/table_row.tsx | 2 +- .../__snapshots__/json_code_block.test.tsx.snap | 1 + .../components/json_code_block/json_code_block.tsx | 2 +- .../components/sidebar/discover_sidebar.scss | 2 ++ .../components/top_nav/get_top_nav_links.tsx | 2 +- .../inspector/public/ui/inspector_view_chooser.tsx | 13 ++++++++----- 15 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 changelogs/fragments/7299.yml diff --git a/changelogs/fragments/7299.yml b/changelogs/fragments/7299.yml new file mode 100644 index 000000000000..bda41acd6d58 --- /dev/null +++ b/changelogs/fragments/7299.yml @@ -0,0 +1,2 @@ +refactor: +- Density and consistency changes for discover and query bar ([#7299](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7299)) \ No newline at end of file diff --git a/src/plugins/data/public/ui/filter_bar/_global_filter_group.scss b/src/plugins/data/public/ui/filter_bar/_global_filter_group.scss index f1af6e7f9b7e..9b25e874b190 100644 --- a/src/plugins/data/public/ui/filter_bar/_global_filter_group.scss +++ b/src/plugins/data/public/ui/filter_bar/_global_filter_group.scss @@ -32,10 +32,8 @@ } .globalFilterGroup__branch { - padding: $euiSizeS $euiSizeM 0 0; - background-repeat: no-repeat; - background-position: $euiSizeM ($euiSizeS * -1); - background-image: url("data:image/svg+xml,%0A%3Csvg width='28px' height='28px' viewBox='0 0 28 28' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='#{hexToRGB($euiColorLightShade)}'%3E%3Crect x='14' y='27' width='14' height='1'%3E%3C/rect%3E%3C/g%3E%3C/svg%3E"); + // matches inline #GlobalFilterGroup height and same size as add filter button + padding to vertically center + line-height: 40px; } .globalFilterGroup__wrapper { diff --git a/src/plugins/data/public/ui/filter_bar/_global_filter_item.scss b/src/plugins/data/public/ui/filter_bar/_global_filter_item.scss index 25cdce24aa8e..0afa48e428e1 100644 --- a/src/plugins/data/public/ui/filter_bar/_global_filter_item.scss +++ b/src/plugins/data/public/ui/filter_bar/_global_filter_item.scss @@ -83,7 +83,7 @@ } .globalFilterItem__editorForm { - padding: $euiSizeM; + padding: $euiSizeS; } .globalFilterItem__popover, diff --git a/src/plugins/data/public/ui/filter_bar/filter_bar.tsx b/src/plugins/data/public/ui/filter_bar/filter_bar.tsx index a423b1714a4d..964b1fe82fb7 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_bar.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_bar.tsx @@ -110,15 +110,15 @@ function FilterBarUI(props: Props) { const button = ( setIsAddFilterPopoverOpen(true)} data-test-subj="addFilter" aria-label={i18n.translate('data.filter.filterBar.addFilterButtonLabel', { defaultMessage: 'Add filter', })} className="globalFilterBar__addButton" + iconType="plusInCircle" > - +{' '} { public render() { return (
- + - + + +

diff --git a/src/plugins/discover/public/application/components/json_code_block/__snapshots__/json_code_block.test.tsx.snap b/src/plugins/discover/public/application/components/json_code_block/__snapshots__/json_code_block.test.tsx.snap index 3897e22c50f1..4247a7b03084 100644 --- a/src/plugins/discover/public/application/components/json_code_block/__snapshots__/json_code_block.test.tsx.snap +++ b/src/plugins/discover/public/application/components/json_code_block/__snapshots__/json_code_block.test.tsx.snap @@ -3,6 +3,7 @@ exports[`returns the \`JsonCodeEditor\` component 1`] = ` + {stringify(hit, null, 2)} ); diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss index b0bffeb2b216..58f168ea88d3 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss +++ b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss @@ -2,6 +2,8 @@ width: 100%; .euiButtonEmpty__content { + font-size: $euiFontSizeXS; + font-weight: $euiFontWeightSemiBold; justify-content: flex-end; } } diff --git a/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.tsx b/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.tsx index 6a5f815f9b3d..592cc23afffc 100644 --- a/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.tsx +++ b/src/plugins/discover/public/application/components/top_nav/get_top_nav_links.tsx @@ -241,7 +241,7 @@ export const getTopNavLinks = ( }), run() { inspector.open(inspectorAdapters, { - title: savedSearch?.title, + title: savedSearch?.title || undefined, }); }, }; diff --git a/src/plugins/inspector/public/ui/inspector_view_chooser.tsx b/src/plugins/inspector/public/ui/inspector_view_chooser.tsx index 2f6bf71a5ada..5018969de94e 100644 --- a/src/plugins/inspector/public/ui/inspector_view_chooser.tsx +++ b/src/plugins/inspector/public/ui/inspector_view_chooser.tsx @@ -36,6 +36,7 @@ import { EuiContextMenuItem, EuiContextMenuPanel, EuiPopover, + EuiText, EuiToolTip, } from '@elastic/eui'; import { InspectorViewDescription } from '../types'; @@ -111,11 +112,13 @@ export class InspectorViewChooser extends Component { renderSingleView() { return ( - + + + ); } From f1ae46ea427bbc4036fd5281702a022ce7b3592b Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sat, 20 Jul 2024 10:29:27 +0800 Subject: [PATCH 084/276] [workspace] Fix not able to query legacy data when have at least 1 workspace (#7254) (#7320) * Fix not able to query legacy data when have at least 1 workspace * fix typo * update snapshot --------- (cherry picked from commit 3bb41703c42478b778cbcf98a4231726767373ae) Signed-off-by: Hailong Cui Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: Yulong Ruan --- .../__snapshots__/feature_cards.test.tsx.snap | 18 +++++++++++++- .../public/lib/get_saved_object_counts.ts | 1 + .../saved_objects_table.test.tsx | 6 ++--- .../objects_table/saved_objects_table.tsx | 13 +++++----- .../public/utils.test.ts | 24 +++++++++++++++++++ .../saved_objects_management/public/utils.ts | 10 ++++---- .../server/routes/scroll_count.ts | 7 ++++-- 7 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/plugins/management/public/components/feature_cards/__snapshots__/feature_cards.test.tsx.snap b/src/plugins/management/public/components/feature_cards/__snapshots__/feature_cards.test.tsx.snap index d777d7d9e2c0..0718fb98bf4f 100644 --- a/src/plugins/management/public/components/feature_cards/__snapshots__/feature_cards.test.tsx.snap +++ b/src/plugins/management/public/components/feature_cards/__snapshots__/feature_cards.test.tsx.snap @@ -3,7 +3,23 @@ exports[` render with complex navLinks 1`] = `
+
+
+

+

+
+
+
diff --git a/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts b/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts index 374f2720b537..b46389fe54f3 100644 --- a/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts +++ b/src/plugins/saved_objects_management/public/lib/get_saved_object_counts.ts @@ -35,6 +35,7 @@ export interface SavedObjectCountOptions { namespacesToInclude?: string[]; searchString?: string; workspaces?: string[]; + availableWorkspaces?: string[]; } export async function getSavedObjectCounts( diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx index bee992e0196d..a33a59786617 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.test.tsx @@ -812,7 +812,7 @@ describe('SavedObjectsTable', () => { }); }); - it('all visible workspaces in find options when not in any workspace', async () => { + it('no workspaces in find options when not in any workspace', async () => { findObjectsMock.mockClear(); const applications = applicationServiceMock.createStartContract(); applications.capabilities = { @@ -851,8 +851,8 @@ describe('SavedObjectsTable', () => { await waitFor(() => { expect(findObjectsMock).toBeCalledWith( http, - expect.objectContaining({ - workspaces: expect.arrayContaining(['workspace1', 'workspace2']), + expect.not.objectContaining({ + workspaces, }) ); }); diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx index 162daab66e56..38f69a05b35c 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx @@ -187,15 +187,14 @@ export class SavedObjectsTable extends Component ws.id); + return undefined; } else { return [currentWorkspaceId]; } @@ -250,6 +249,7 @@ export class SavedObjectsTable extends Component ws.id), }); if (availableNamespaces.length) { @@ -286,6 +286,7 @@ export class SavedObjectsTable extends Component ws.id), }); if (availableNamespaces.length) { @@ -958,9 +959,7 @@ export class SavedObjectsTable extends Component { - return this.workspaceIdQuery?.includes(ws.id); - }) + .filter((ws) => (currentWorkspaceId ? currentWorkspaceId === ws.id : true)) .map((ws) => { return { name: ws.name, diff --git a/src/plugins/saved_objects_management/public/utils.test.ts b/src/plugins/saved_objects_management/public/utils.test.ts index 3b714a169219..eebfdec8f61d 100644 --- a/src/plugins/saved_objects_management/public/utils.test.ts +++ b/src/plugins/saved_objects_management/public/utils.test.ts @@ -17,4 +17,28 @@ describe('Utils', () => { const obj = formatWorkspaceIdParams({ foo: 'bar', workspaces: ['foo'] }); expect(obj).toEqual({ foo: 'bar', workspaces: ['foo'] }); }); + + it('formatWorkspaceIdParams with availableWorkspaces exists', async () => { + const obj = formatWorkspaceIdParams({ foo: 'bar', availableWorkspaces: ['foo'] }); + expect(obj).toEqual({ foo: 'bar', availableWorkspaces: ['foo'] }); + }); + + it('formatWorkspaceIdParams with availableWorkspaces is empty array', async () => { + const obj = formatWorkspaceIdParams({ foo: 'bar', availableWorkspaces: [] }); + expect(obj).toEqual({ foo: 'bar' }); + }); + + it('formatWorkspaceIdParams with availableWorkspaces is null/undefined', async () => { + const obj = formatWorkspaceIdParams({ foo: 'bar', availableWorkspaces: null }); + expect(obj).toEqual({ foo: 'bar' }); + }); + + it('formatWorkspaceIdParams with both workspaces and availableWorkspaces are not empty', async () => { + const obj = formatWorkspaceIdParams({ + foo: 'bar', + availableWorkspaces: ['foo', 'bar'], + workspaces: ['foo'], + }); + expect(obj).toEqual({ foo: 'bar', availableWorkspaces: ['foo', 'bar'], workspaces: ['foo'] }); + }); }); diff --git a/src/plugins/saved_objects_management/public/utils.ts b/src/plugins/saved_objects_management/public/utils.ts index 84727ab6a356..937e7767702d 100644 --- a/src/plugins/saved_objects_management/public/utils.ts +++ b/src/plugins/saved_objects_management/public/utils.ts @@ -3,11 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -export function formatWorkspaceIdParams( - obj: T -): T | Omit { - const { workspaces, ...others } = obj; - if (workspaces) { +export function formatWorkspaceIdParams< + T extends { workspaces?: string[] | null; availableWorkspaces?: string[] | null } +>(obj: T): T | Omit { + const { workspaces, availableWorkspaces, ...others } = obj; + if (workspaces || (availableWorkspaces && availableWorkspaces.length)) { return obj; } return others; diff --git a/src/plugins/saved_objects_management/server/routes/scroll_count.ts b/src/plugins/saved_objects_management/server/routes/scroll_count.ts index fc5237805378..c200d6c82dd1 100644 --- a/src/plugins/saved_objects_management/server/routes/scroll_count.ts +++ b/src/plugins/saved_objects_management/server/routes/scroll_count.ts @@ -42,6 +42,7 @@ export const registerScrollForCountRoute = (router: IRouter) => { namespacesToInclude: schema.maybe(schema.arrayOf(schema.string())), searchString: schema.maybe(schema.string()), workspaces: schema.maybe(schema.arrayOf(schema.string())), + availableWorkspaces: schema.maybe(schema.arrayOf(schema.string())), }), }, }, @@ -59,7 +60,9 @@ export const registerScrollForCountRoute = (router: IRouter) => { const requestHasNamespaces = Array.isArray(req.body.namespacesToInclude) && req.body.namespacesToInclude.length; - const requestHasWorkspaces = Array.isArray(req.body.workspaces) && req.body.workspaces.length; + const requestHasWorkspaces = + (Array.isArray(req.body.workspaces) && req.body.workspaces.length) || + (Array.isArray(req.body.availableWorkspaces) && req.body.availableWorkspaces.length); if (requestHasNamespaces) { counts.namespaces = {}; @@ -114,7 +117,7 @@ export const registerScrollForCountRoute = (router: IRouter) => { } } - const workspacesToInclude = req.body.workspaces || []; + const workspacesToInclude = req.body.workspaces || req.body.availableWorkspaces || []; for (const ws of workspacesToInclude) { if (!counts.workspaces[ws]) { counts.workspaces[ws] = 0; From d84a5aa1e5146c5b877b51104059764378d4dedb Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:55:51 +0800 Subject: [PATCH 085/276] [Workspace] use registered nav groups in workspace form (#7221) (#7317) * Add registered use cases * Separate use case service and fix UTs * Add test case for workspace plugin * Fix workspace unit tests * Changeset file for PR #7221 created/updated * Remove workspaceConfigurableApp$ in component * Remove no need workspaceConfigurableApps$ and add navGroupUpdater ut * Fix type error * Remove centered horizontal position * Fix isDashboardAdmin in workspace creator unit tests * Fix dynamic nav groups missing in workspace list --------- (cherry picked from commit fceba91ba2c55c03efd48c82c795f9c557d8af84) Signed-off-by: Lin Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7221.yml | 2 + src/plugins/workspace/public/application.tsx | 10 +- .../workspace_creator.test.tsx | 74 +++---- .../workspace_creator/workspace_creator.tsx | 14 +- .../workspace_detail.test.tsx | 14 +- .../workspace_detail/workspace_detail.tsx | 9 +- .../workspace_updater.test.tsx | 68 +++--- .../workspace_detail/workspace_updater.tsx | 11 +- .../public/components/workspace_form/types.ts | 9 +- .../workspace_form/workspace_detail_form.tsx | 4 +- .../workspace_form/workspace_form.test.tsx | 4 + .../workspace_form/workspace_form.tsx | 4 +- .../workspace_use_case.test.tsx | 13 +- .../workspace_form/workspace_use_case.tsx | 54 ++--- .../components/workspace_list/index.test.tsx | 24 ++- .../components/workspace_list/index.tsx | 23 +- .../public/components/workspace_list_app.tsx | 8 +- src/plugins/workspace/public/plugin.test.ts | 111 +++++++++- src/plugins/workspace/public/plugin.ts | 70 +++++-- .../public/services/use_case_service.test.ts | 120 +++++++++++ .../public/services/use_case_service.ts | 73 +++++++ src/plugins/workspace/public/types.ts | 9 + src/plugins/workspace/public/utils.test.ts | 196 ++++++++++++++++-- src/plugins/workspace/public/utils.ts | 82 ++++++-- 24 files changed, 759 insertions(+), 247 deletions(-) create mode 100644 changelogs/fragments/7221.yml create mode 100644 src/plugins/workspace/public/services/use_case_service.test.ts create mode 100644 src/plugins/workspace/public/services/use_case_service.ts diff --git a/changelogs/fragments/7221.yml b/changelogs/fragments/7221.yml new file mode 100644 index 000000000000..f173960109d7 --- /dev/null +++ b/changelogs/fragments/7221.yml @@ -0,0 +1,2 @@ +feat: +- Use registered nav group as workspace use case ([#7221](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7221)) \ No newline at end of file diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index 717c0aadd623..3e9cb3a506eb 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -9,7 +9,7 @@ import { AppMountParameters, ScopedHistory } from '../../../core/public'; import { OpenSearchDashboardsContextProvider } from '../../opensearch_dashboards_react/public'; import { WorkspaceFatalError } from './components/workspace_fatal_error'; import { WorkspaceCreatorApp } from './components/workspace_creator_app'; -import { WorkspaceListApp } from './components/workspace_list_app'; +import { WorkspaceListApp, WorkspaceListAppProps } from './components/workspace_list_app'; import { Services } from './types'; import { WorkspaceCreatorProps } from './components/workspace_creator/workspace_creator'; import { WorkspaceDetailApp } from './components/workspace_detail_app'; @@ -46,10 +46,14 @@ export const renderFatalErrorApp = (params: AppMountParameters, services: Servic ReactDOM.unmountComponentAtNode(element); }; }; -export const renderListApp = ({ element }: AppMountParameters, services: Services) => { +export const renderListApp = ( + { element }: AppMountParameters, + services: Services, + props: WorkspaceListAppProps +) => { ReactDOM.render( - + , element ); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx index ad3b79da4788..8550e0c4fa91 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx @@ -7,9 +7,13 @@ import React from 'react'; import { PublicAppInfo } from 'opensearch-dashboards/public'; import { fireEvent, render, waitFor, act } from '@testing-library/react'; import { BehaviorSubject } from 'rxjs'; -import { WorkspaceCreator as WorkspaceCreatorComponent } from './workspace_creator'; +import { + WorkspaceCreator as WorkspaceCreatorComponent, + WorkspaceCreatorProps, +} from './workspace_creator'; import { coreMock } from '../../../../../core/public/mocks'; import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; +import { WORKSPACE_USE_CASES } from '../../../common/constants'; const workspaceClientCreate = jest .fn() @@ -43,7 +47,10 @@ const dataSourcesList = [ const mockCoreStart = coreMock.createStart(); -const WorkspaceCreator = (props: any, isDashboardAdmin = false) => { +const WorkspaceCreator = ({ + isDashboardAdmin = false, + ...props +}: Partial) => { const { Provider } = createOpenSearchDashboardsReactContext({ ...mockCoreStart, ...{ @@ -86,10 +93,16 @@ const WorkspaceCreator = (props: any, isDashboardAdmin = false) => { dataSourceManagement: {}, }, }); + const registeredUseCases$ = new BehaviorSubject([ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.analytics, + WORKSPACE_USE_CASES.search, + ]); return ( - + ); }; @@ -122,21 +135,13 @@ describe('WorkspaceCreator', () => { }); it('should not create workspace when name is empty', async () => { - const { getByTestId } = render( - - ); + const { getByTestId } = render(); fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); expect(workspaceClientCreate).not.toHaveBeenCalled(); }); it('should not create workspace with invalid name', async () => { - const { getByTestId } = render( - - ); + const { getByTestId } = render(); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: '~' }, @@ -146,11 +151,7 @@ describe('WorkspaceCreator', () => { it('should not create workspace without use cases', async () => { setHrefSpy.mockReset(); - const { getByTestId } = render( - - ); + const { getByTestId } = render(); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -161,11 +162,7 @@ describe('WorkspaceCreator', () => { }); it('cancel create workspace', async () => { - const { findByText, getByTestId } = render( - - ); + const { findByText, getByTestId } = render(); fireEvent.click(getByTestId('workspaceForm-bottomBar-cancelButton')); await findByText('Discard changes?'); fireEvent.click(getByTestId('confirmModalConfirmButton')); @@ -173,11 +170,7 @@ describe('WorkspaceCreator', () => { }); it('create workspace with detailed information', async () => { - const { getByTestId } = render( - - ); + const { getByTestId } = render(); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -217,11 +210,7 @@ describe('WorkspaceCreator', () => { it('should show danger toasts after create workspace failed', async () => { workspaceClientCreate.mockReturnValueOnce({ result: { id: 'failResult' }, success: false }); - const { getByTestId } = render( - - ); + const { getByTestId } = render(); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -239,11 +228,7 @@ describe('WorkspaceCreator', () => { workspaceClientCreate.mockImplementationOnce(async () => { throw new Error(); }); - const { getByTestId } = render( - - ); + const { getByTestId } = render(); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -257,12 +242,8 @@ describe('WorkspaceCreator', () => { expect(notificationToastsAddSuccess).not.toHaveBeenCalled(); }); - it('create workspace with current user', async () => { - const { getByTestId } = render( - - ); + it('create workspace with customized permissions', async () => { + const { getByTestId } = render(); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -294,10 +275,7 @@ describe('WorkspaceCreator', () => { it('create workspace with customized selected dataSources', async () => { const { getByTestId, getByTitle, getByText } = render( - + ); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx index 9d4ccaaef1cb..88c46e973c00 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx @@ -7,9 +7,8 @@ import React, { useCallback } from 'react'; import { EuiPage, EuiPageBody, EuiPageHeader, EuiPageContent } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { useObservable } from 'react-use'; -import { BehaviorSubject, of } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; -import { PublicAppInfo } from 'opensearch-dashboards/public'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { WorkspaceForm, WorkspaceFormSubmitData, WorkspaceOperationType } from '../workspace_form'; import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants'; @@ -18,9 +17,10 @@ import { WorkspaceClient } from '../../workspace_client'; import { convertPermissionSettingsToPermissions } from '../workspace_form'; import { DataSource } from '../../../common/types'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; +import { WorkspaceUseCase } from '../../types'; export interface WorkspaceCreatorProps { - workspaceConfigurableApps$?: BehaviorSubject; + registeredUseCases$: BehaviorSubject; } export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { @@ -37,10 +37,8 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { workspaceClient: WorkspaceClient; dataSourceManagement?: DataSourceManagementPluginSetup; }>(); - const workspaceConfigurableApps = useObservable( - props.workspaceConfigurableApps$ ?? of(undefined) - ); const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; + const availableUseCases = useObservable(props.registeredUseCases$, []); const handleWorkspaceFormSubmit = useCallback( async (data: WorkspaceFormSubmitData) => { @@ -96,7 +94,6 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { { savedObjects={savedObjects} onSubmit={handleWorkspaceFormSubmit} operationType={WorkspaceOperationType.Create} - workspaceConfigurableApps={workspaceConfigurableApps} permissionEnabled={isPermissionEnabled} - permissionLastAdminItemDeletable dataSourceManagement={dataSourceManagement} + availableUseCases={availableUseCases} /> )} diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx index 8b2937abd6c2..030cc03fee99 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx @@ -5,10 +5,11 @@ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; import React from 'react'; -import { coreMock } from '../../../../../core/public/mocks'; -import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; import { BehaviorSubject } from 'rxjs'; import { PublicAppInfo, WorkspaceObject } from 'opensearch-dashboards/public'; +import { coreMock } from '../../../../../core/public/mocks'; +import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; +import { WORKSPACE_USE_CASES } from '../../../common/constants'; import { WorkspaceDetail } from './workspace_detail'; // all applications @@ -71,9 +72,16 @@ const WorkspaceDetailPage = (props: any) => { }, }); + const registeredUseCases$ = new BehaviorSubject([ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.analytics, + WORKSPACE_USE_CASES.search, + ]); + return ( - + ); }; diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx index efa5e5a68194..8e1df0bd6372 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx @@ -16,15 +16,16 @@ import { import { useObservable } from 'react-use'; import { i18n } from '@osd/i18n'; -import { CoreStart, PublicAppInfo } from 'opensearch-dashboards/public'; +import { CoreStart } from 'opensearch-dashboards/public'; import { BehaviorSubject } from 'rxjs'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { WorkspaceUseCase } from '../../types'; import { WorkspaceDetailContent } from './workspace_detail_content'; import { WorkspaceUpdater } from './workspace_updater'; import { DetailTab } from '../workspace_form/constants'; export interface WorkspaceDetailProps { - workspaceConfigurableApps$?: BehaviorSubject; + registeredUseCases$: BehaviorSubject; } export const WorkspaceDetail = (props: WorkspaceDetailProps) => { @@ -60,8 +61,8 @@ export const WorkspaceDetail = (props: WorkspaceDetailProps) => { }), content: ( ), }, @@ -74,8 +75,8 @@ export const WorkspaceDetail = (props: WorkspaceDetailProps) => { }), content: ( ), }, diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx index 707f72e17ce6..8f28fdd816dc 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx @@ -7,10 +7,15 @@ import React from 'react'; import { PublicAppInfo, WorkspaceObject } from 'opensearch-dashboards/public'; import { fireEvent, render, waitFor, screen, act } from '@testing-library/react'; import { BehaviorSubject } from 'rxjs'; -import { WorkspaceUpdater as WorkspaceUpdaterComponent } from './workspace_updater'; + import { coreMock, workspacesServiceMock } from '../../../../../core/public/mocks'; import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; import { DetailTab } from '../workspace_form/constants'; +import { WORKSPACE_USE_CASES } from '../../../common/constants'; +import { + WorkspaceUpdater as WorkspaceUpdaterComponent, + WorkspaceUpdaterProps, +} from './workspace_updater'; const workspaceClientUpdate = jest.fn().mockReturnValue({ result: true, success: true }); @@ -70,7 +75,11 @@ const mockCoreStart = coreMock.createStart(); const renderCompleted = () => expect(screen.queryByText('Enter details')).not.toBeNull(); -const WorkspaceUpdater = (props: any) => { +const WorkspaceUpdater = ( + props: Partial & { + workspacesService?: ReturnType; + } +) => { const workspacesService = props.workspacesService || createWorkspacesSetupContractMockWithValue(); const { Provider } = createOpenSearchDashboardsReactContext({ ...mockCoreStart, @@ -115,10 +124,16 @@ const WorkspaceUpdater = (props: any) => { dataSourceManagement: {}, }, }); + const registeredUseCases$ = new BehaviorSubject([ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.analytics, + WORKSPACE_USE_CASES.search, + ]); return ( - + ); }; @@ -154,7 +169,6 @@ describe('WorkspaceUpdater', () => { const mockedWorkspacesService = workspacesServiceMock.createSetupContract(); const { container } = render( @@ -163,12 +177,7 @@ describe('WorkspaceUpdater', () => { }); it('cannot update workspace with invalid name', async () => { - const { getByTestId } = render( - - ); + const { getByTestId } = render(); await waitFor(renderCompleted); @@ -180,12 +189,7 @@ describe('WorkspaceUpdater', () => { }); it('cancel update workspace', async () => { - const { findByText, getByTestId } = render( - - ); + const { findByText, getByTestId } = render(); await waitFor(renderCompleted); fireEvent.click(getByTestId('workspaceForm-bottomBar-cancelButton')); @@ -194,12 +198,9 @@ describe('WorkspaceUpdater', () => { expect(navigateToApp).toHaveBeenCalled(); }); - it('update workspace successfully without permission', async () => { + it('update workspace successfully', async () => { const { getByTestId, getAllByLabelText } = render( - + ); await waitFor(renderCompleted); @@ -258,10 +259,7 @@ describe('WorkspaceUpdater', () => { it('update workspace permission successfully', async () => { const { getByTestId, getAllByTestId } = render( - + ); await waitFor(() => expect(screen.queryByText('Manage access and permissions')).not.toBeNull()); @@ -304,12 +302,7 @@ describe('WorkspaceUpdater', () => { it('should show danger toasts after update workspace failed', async () => { workspaceClientUpdate.mockReturnValue({ result: false, success: false }); - const { getByTestId } = render( - - ); + const { getByTestId } = render(); await waitFor(renderCompleted); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); @@ -328,12 +321,7 @@ describe('WorkspaceUpdater', () => { workspaceClientUpdate.mockImplementation(() => { throw new Error('update workspace failed'); }); - const { getByTestId } = render( - - ); + const { getByTestId } = render(); await waitFor(renderCompleted); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); @@ -351,11 +339,7 @@ describe('WorkspaceUpdater', () => { it('should show danger toasts when currentWorkspace is missing after click update button', async () => { const mockedWorkspacesService = workspacesServiceMock.createSetupContract(); const { getByTestId } = render( - + ); await waitFor(renderCompleted); diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx index f0c4869f441f..7ba838303a89 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx @@ -6,7 +6,6 @@ import React, { useCallback, useEffect, useState } from 'react'; import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { PublicAppInfo } from 'opensearch-dashboards/public'; import { useObservable } from 'react-use'; import { BehaviorSubject, of } from 'rxjs'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; @@ -25,9 +24,10 @@ import { getDataSourcesList } from '../../utils'; import { DataSource } from '../../../common/types'; import { DetailTab } from '../workspace_form/constants'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; +import { WorkspaceUseCase } from '../../types'; export interface WorkspaceUpdaterProps { - workspaceConfigurableApps$?: BehaviorSubject; + registeredUseCases$: BehaviorSubject; detailTab?: DetailTab; } @@ -66,9 +66,7 @@ export const WorkspaceUpdater = (props: WorkspaceUpdaterProps) => { }>(); const currentWorkspace = useObservable(workspaces ? workspaces.currentWorkspace$ : of(null)); - const workspaceConfigurableApps = useObservable( - props.workspaceConfigurableApps$ ?? of(undefined) - ); + const availableUseCases = useObservable(props.registeredUseCases$, []); const [currentWorkspaceFormData, setCurrentWorkspaceFormData] = useState(); const handleWorkspaceFormSubmit = useCallback( @@ -150,7 +148,6 @@ export const WorkspaceUpdater = (props: WorkspaceUpdaterProps) => { { defaultValues={currentWorkspaceFormData} onSubmit={handleWorkspaceFormSubmit} operationType={WorkspaceOperationType.Update} - workspaceConfigurableApps={workspaceConfigurableApps} savedObjects={savedObjects} detailTab={props.detailTab} dataSourceManagement={dataSourceManagement} + availableUseCases={availableUseCases} /> )} diff --git a/src/plugins/workspace/public/components/workspace_form/types.ts b/src/plugins/workspace/public/components/workspace_form/types.ts index 64010f90ef7b..0e2ab1631fc9 100644 --- a/src/plugins/workspace/public/components/workspace_form/types.ts +++ b/src/plugins/workspace/public/components/workspace_form/types.ts @@ -3,15 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type { - ApplicationStart, - PublicAppInfo, - SavedObjectsStart, -} from '../../../../../core/public'; +import type { ApplicationStart, SavedObjectsStart } from '../../../../../core/public'; import type { WorkspacePermissionMode } from '../../../common/constants'; import type { DetailTab, WorkspaceOperationType, WorkspacePermissionItemType } from './constants'; import { DataSource } from '../../../common/types'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; +import { WorkspaceUseCase } from '../../types'; export interface WorkspaceUserPermissionSetting { id: number; @@ -84,8 +81,8 @@ export interface WorkspaceFormProps { onSubmit?: (formData: WorkspaceFormSubmitData) => void; defaultValues?: WorkspaceFormData; operationType: WorkspaceOperationType; - workspaceConfigurableApps?: PublicAppInfo[]; permissionEnabled?: boolean; detailTab?: DetailTab; dataSourceManagement?: DataSourceManagementPluginSetup; + availableUseCases: WorkspaceUseCase[]; } diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx index 1369abca517e..2e8b7cb32415 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx @@ -48,7 +48,7 @@ export const WorkspaceDetailForm = (props: WorkspaceFormProps) => { savedObjects, defaultValues, operationType, - workspaceConfigurableApps, + availableUseCases, dataSourceManagement: isDataSourceEnabled, } = props; const { @@ -109,10 +109,10 @@ export const WorkspaceDetailForm = (props: WorkspaceFormProps) => { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx index ad79181af285..f9b6fea2e66e 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx @@ -8,6 +8,8 @@ import { render } from '@testing-library/react'; import { WorkspaceForm } from './workspace_form'; import { coreMock } from '../../../../../core/public/mocks'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; +import { WORKSPACE_USE_CASES } from '../../../common/constants'; +import { WorkspaceOperationType } from './constants'; const mockCoreStart = coreMock.createStart(); @@ -38,6 +40,8 @@ const setup = ( ); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index 25381fd94e6c..07c86ef15ab0 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -30,8 +30,8 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { defaultValues, operationType, permissionEnabled, - workspaceConfigurableApps, dataSourceManagement: isDataSourceEnabled, + availableUseCases, } = props; const { formId, @@ -85,10 +85,10 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx index d758c3ee0d60..7aa04a547c2c 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx @@ -5,6 +5,7 @@ import React from 'react'; import { fireEvent, render } from '@testing-library/react'; +import { WORKSPACE_USE_CASES } from '../../../common/constants'; import { WorkspaceUseCase, WorkspaceUseCaseProps } from './workspace_use_case'; import { WorkspaceFormErrors } from './types'; @@ -13,9 +14,17 @@ const setup = (options?: Partial) => { const formErrors: WorkspaceFormErrors = {}; const renderResult = render( void; formErrors: WorkspaceFormErrors; + availableUseCases: WorkspaceUseCaseObject[]; } export const WorkspaceUseCase = ({ - configurableApps, value, onChange, formErrors, + availableUseCases, }: WorkspaceUseCaseProps) => { - const availableUseCases = useMemo(() => { - if (!configurableApps) { - return []; - } - const configurableAppsId = configurableApps.map((app) => app.id); - return ALL_USE_CASES.filter((useCase) => { - return useCase.features.some((featureId) => configurableAppsId.includes(featureId)); - }); - }, [configurableApps]); - const handleCardChange = useCallback( (id: string) => { if (!value.includes(id)) { @@ -98,17 +80,19 @@ export const WorkspaceUseCase = ({ fullWidth > - {availableUseCases.map(({ id, title, description }) => ( - - - - ))} + {availableUseCases + .filter((item) => !item.systematic) + .map(({ id, title, description }) => ( + + + + ))} ); diff --git a/src/plugins/workspace/public/components/workspace_list/index.test.tsx b/src/plugins/workspace/public/components/workspace_list/index.test.tsx index c716c745736a..5e55205c196e 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.test.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.test.tsx @@ -4,15 +4,14 @@ */ import React from 'react'; -import { WorkspaceList } from './index'; -import { coreMock } from '../../../../../core/public/mocks'; +import { BehaviorSubject, of } from 'rxjs'; import { render, fireEvent, screen } from '@testing-library/react'; import { I18nProvider } from '@osd/i18n/react'; +import { coreMock } from '../../../../../core/public/mocks'; import { navigateToWorkspaceDetail } from '../utils/workspace'; - -import { of } from 'rxjs'; - import { OpenSearchDashboardsContextProvider } from '../../../../../plugins/opensearch_dashboards_react/public'; +import { WORKSPACE_USE_CASES } from '../../../common/constants'; +import { WorkspaceList } from './index'; jest.mock('../utils/workspace'); @@ -43,7 +42,9 @@ function getWrapWorkspaceListInContext( return ( - + ); @@ -51,15 +52,24 @@ function getWrapWorkspaceListInContext( describe('WorkspaceList', () => { it('should render title and table normally', () => { - const { getByText, getByRole, container } = render(); + const { getByText, getByRole, container } = render( + + ); expect(getByText('Workspaces')).toBeInTheDocument(); expect(getByRole('table')).toBeInTheDocument(); expect(container).toMatchSnapshot(); }); it('should render data in table based on workspace list data', async () => { const { getByText } = render(getWrapWorkspaceListInContext()); + + // should display workspace names expect(getByText('name1')).toBeInTheDocument(); expect(getByText('name2')).toBeInTheDocument(); + + // should display use case + expect(getByText('Observability')).toBeInTheDocument(); }); it('should be able to apply debounce search after input', async () => { const list = [ diff --git a/src/plugins/workspace/public/components/workspace_list/index.tsx b/src/plugins/workspace/public/components/workspace_list/index.tsx index 563a90f04970..0d2e3c79082d 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.tsx @@ -15,28 +15,34 @@ import { EuiSearchBarProps, } from '@elastic/eui'; import useObservable from 'react-use/lib/useObservable'; -import { of } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; import { i18n } from '@osd/i18n'; import { debounce } from '../../../../../core/public'; import { WorkspaceAttribute } from '../../../../../core/public'; import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public'; import { navigateToWorkspaceDetail } from '../utils/workspace'; -import { WORKSPACE_CREATE_APP_ID, WORKSPACE_USE_CASES } from '../../../common/constants'; +import { WORKSPACE_CREATE_APP_ID } from '../../../common/constants'; import { cleanWorkspaceId } from '../../../../../core/public'; import { DeleteWorkspaceModal } from '../delete_workspace_modal'; -import { getUseCaseFromFeatureConfig, isUseCaseFeatureConfig } from '../../utils'; +import { getUseCaseFromFeatureConfig } from '../../utils'; +import { WorkspaceUseCase } from '../../types'; -const WORKSPACE_LIST_PAGE_DESCRIPTIOIN = i18n.translate('workspace.list.description', { +const WORKSPACE_LIST_PAGE_DESCRIPTION = i18n.translate('workspace.list.description', { defaultMessage: 'Workspace allow you to save and organize library items, such as index patterns, visualizations, dashboards, saved searches, and share them with other OpenSearch Dashboards users. You can control which features are visible in each workspace, and which users and groups have read and write access to the library items in the workspace.', }); -export const WorkspaceList = () => { +export interface WorkspaceListProps { + registeredUseCases$: BehaviorSubject; +} + +export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { const { services: { workspaces, application, http }, } = useOpenSearchDashboards(); + const registeredUseCases = useObservable(registeredUseCases$); const initialSortField = 'name'; const initialSortDirection = 'asc'; @@ -106,7 +112,10 @@ export const WorkspaceList = () => { features.forEach((featureConfig) => { const useCaseId = getUseCaseFromFeatureConfig(featureConfig); if (useCaseId) { - results.push(WORKSPACE_USE_CASES[useCaseId].title); + const useCase = registeredUseCases?.find(({ id }) => id === useCaseId); + if (useCase) { + results.push(useCase.title); + } } }); return results.join(', '); @@ -182,7 +191,7 @@ export const WorkspaceList = () => { { +export type WorkspaceListAppProps = WorkspaceListProps; + +export const WorkspaceListApp = (props: WorkspaceListAppProps) => { const { services: { chrome }, } = useOpenSearchDashboards(); @@ -29,7 +31,7 @@ export const WorkspaceListApp = () => { return ( - + ); }; diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 7af07fee7fed..b732280b92c8 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -5,14 +5,21 @@ import { BehaviorSubject, Observable, Subscriber } from 'rxjs'; import { waitFor } from '@testing-library/dom'; -import { ChromeBreadcrumb } from 'opensearch-dashboards/public'; -import { workspaceClientMock, WorkspaceClientMock } from './workspace_client.mock'; +import { first } from 'rxjs/operators'; + import { applicationServiceMock, chromeServiceMock, coreMock } from '../../../core/public/mocks'; -import { DEFAULT_NAV_GROUPS, AppNavLinkStatus } from '../../../core/public'; -import { WorkspacePlugin } from './plugin'; +import { + ChromeBreadcrumb, + NavGroupStatus, + DEFAULT_NAV_GROUPS, + AppNavLinkStatus, +} from '../../../core/public'; import { WORKSPACE_FATAL_ERROR_APP_ID, WORKSPACE_DETAIL_APP_ID } from '../common/constants'; import { savedObjectsManagementPluginMock } from '../../saved_objects_management/public/mocks'; import { managementPluginMock } from '../../management/public/mocks'; +import { UseCaseService } from './services/use_case_service'; +import { workspaceClientMock, WorkspaceClientMock } from './workspace_client.mock'; +import { WorkspacePlugin } from './plugin'; describe('Workspace plugin', () => { const getSetupMock = () => ({ @@ -233,6 +240,62 @@ describe('Workspace plugin', () => { }); }); + it('#start should not update systematic use case features after currentWorkspace set', async () => { + const registeredUseCases$ = new BehaviorSubject([ + { + id: 'foo', + title: 'Foo', + features: ['system-feature'], + systematic: true, + }, + ]); + jest.spyOn(UseCaseService.prototype, 'start').mockImplementationOnce(() => ({ + getRegisteredUseCases$: jest.fn(() => registeredUseCases$), + })); + const workspacePlugin = new WorkspacePlugin(); + const setupMock = getSetupMock(); + const coreStart = coreMock.createStart(); + await workspacePlugin.setup(setupMock, {}); + const workspaceObject = { + id: 'foo', + name: 'bar', + features: ['baz'], + }; + coreStart.workspaces.currentWorkspace$.next(workspaceObject); + + const appUpdater$ = setupMock.application.registerAppUpdater.mock.calls[0][0]; + + workspacePlugin.start(coreStart); + + const appUpdater = await appUpdater$.pipe(first()).toPromise(); + + expect(appUpdater({ id: 'system-feature' })).toBeUndefined(); + }); + + it('#start should update nav group status after currentWorkspace set', async () => { + const workspacePlugin = new WorkspacePlugin(); + const setupMock = getSetupMock(); + const coreStart = coreMock.createStart(); + await workspacePlugin.setup(setupMock, {}); + const workspaceObject = { + id: 'foo', + name: 'bar', + features: ['use-case-foo'], + }; + coreStart.workspaces.currentWorkspace$.next(workspaceObject); + + const navGroupUpdater$ = setupMock.chrome.navGroup.registerNavGroupUpdater.mock.calls[0][0]; + + workspacePlugin.start(coreStart); + + const navGroupUpdater = await navGroupUpdater$.pipe(first()).toPromise(); + + expect(navGroupUpdater({ id: 'foo' })).toBeUndefined(); + expect(navGroupUpdater({ id: 'bar' })).toEqual({ + status: NavGroupStatus.Hidden, + }); + }); + it('#stop should call unregisterNavGroupUpdater', async () => { const workspacePlugin = new WorkspacePlugin(); const setupMock = getSetupMock(); @@ -246,4 +309,44 @@ describe('Workspace plugin', () => { expect(unregisterNavGroupUpdater).toHaveBeenCalled(); }); + + it('#stop should not call appUpdater$.next anymore', async () => { + const registeredUseCases$ = new BehaviorSubject([ + { + id: 'foo', + title: 'Foo', + features: ['system-feature'], + systematic: true, + }, + ]); + jest.spyOn(UseCaseService.prototype, 'start').mockImplementationOnce(() => ({ + getRegisteredUseCases$: jest.fn(() => registeredUseCases$), + })); + const workspacePlugin = new WorkspacePlugin(); + const setupMock = getSetupMock(); + const coreStart = coreMock.createStart(); + await workspacePlugin.setup(setupMock, {}); + const workspaceObject = { + id: 'foo', + name: 'bar', + features: ['baz'], + }; + coreStart.workspaces.currentWorkspace$.next(workspaceObject); + + const appUpdater$ = setupMock.application.registerAppUpdater.mock.calls[0][0]; + const appUpdaterChangeMock = jest.fn(); + appUpdater$.subscribe(appUpdaterChangeMock); + + workspacePlugin.start(coreStart); + + // Wait for filterNav been executed + await new Promise(setImmediate); + + expect(appUpdaterChangeMock).toHaveBeenCalledTimes(2); + + workspacePlugin.stop(); + + registeredUseCases$.next([]); + expect(appUpdaterChangeMock).toHaveBeenCalledTimes(2); + }); }); diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index ad1f6f5996c6..ec67754cee3c 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -6,7 +6,7 @@ import { BehaviorSubject, combineLatest, Subscription } from 'rxjs'; import React from 'react'; import { i18n } from '@osd/i18n'; -import { first } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { Plugin, CoreStart, @@ -15,12 +15,12 @@ import { AppNavLinkStatus, AppUpdater, AppStatus, - PublicAppInfo, ChromeBreadcrumb, WorkspaceAvailability, ChromeNavGroupUpdater, NavGroupStatus, DEFAULT_NAV_GROUPS, + NavGroupType, } from '../../../core/public'; import { WORKSPACE_FATAL_ERROR_APP_ID, @@ -29,7 +29,7 @@ import { WORKSPACE_LIST_APP_ID, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; -import { Services } from './types'; +import { Services, WorkspaceUseCase } from './types'; import { WorkspaceClient } from './workspace_client'; import { SavedObjectsManagementPluginSetup } from '../../../plugins/saved_objects_management/public'; import { ManagementSetup } from '../../../plugins/management/public'; @@ -41,11 +41,12 @@ import { isAppAccessibleInWorkspace, isNavGroupInFeatureConfigs, } from './utils'; +import { UseCaseService } from './services/use_case_service'; type WorkspaceAppType = ( params: AppMountParameters, services: Services, - props: Record + props: Record & { registeredUseCases$: BehaviorSubject } ) => () => void; interface WorkspacePluginSetupDeps { @@ -62,8 +63,11 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> private managementCurrentWorkspaceIdSubscription?: Subscription; private appUpdater$ = new BehaviorSubject(() => undefined); private navGroupUpdater$ = new BehaviorSubject(() => undefined); - private workspaceConfigurableApps$ = new BehaviorSubject([]); private unregisterNavGroupUpdater?: () => void; + private registeredUseCases$ = new BehaviorSubject([]); + private registeredUseCasesUpdaterSubscription?: Subscription; + private workspaceAndUseCasesCombineSubscription?: Subscription; + private useCase = new UseCaseService(); private _changeSavedObjectCurrentWorkspace() { if (this.coreStart) { @@ -81,28 +85,42 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> */ private filterNavLinks = (core: CoreStart) => { const currentWorkspace$ = core.workspaces.currentWorkspace$; - this.currentWorkspaceSubscription?.unsubscribe(); - this.currentWorkspaceSubscription = currentWorkspace$.subscribe((currentWorkspace) => { + this.workspaceAndUseCasesCombineSubscription?.unsubscribe(); + this.workspaceAndUseCasesCombineSubscription = combineLatest([ + currentWorkspace$, + this.registeredUseCases$, + ]).subscribe(([currentWorkspace, registeredUseCases]) => { if (currentWorkspace) { this.appUpdater$.next((app) => { - if (isAppAccessibleInWorkspace(app, currentWorkspace)) { + if (isAppAccessibleInWorkspace(app, currentWorkspace, registeredUseCases)) { return; } - if (app.status === AppStatus.inaccessible) { return; } - + if ( + registeredUseCases.some( + (useCase) => useCase.systematic && useCase.features.includes(app.id) + ) + ) { + return; + } /** * Change the app to `inaccessible` if it is not configured in the workspace * If trying to access such app, an "Application Not Found" page will be displayed */ return { status: AppStatus.inaccessible }; }); + } + }); + this.currentWorkspaceSubscription?.unsubscribe(); + this.currentWorkspaceSubscription = currentWorkspace$.subscribe((currentWorkspace) => { + if (currentWorkspace) { this.navGroupUpdater$.next((navGroup) => { if ( + navGroup.type !== NavGroupType.SYSTEM && currentWorkspace.features && !isNavGroupInFeatureConfigs(navGroup.id, currentWorkspace.features) ) { @@ -116,16 +134,12 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> }; /** - * Initiate an observable with the value of all applications which can be configured by workspace + * Return an observable with the value of all applications which can be configured by workspace */ - private setWorkspaceConfigurableApps = async (core: CoreStart) => { - const allApps = await new Promise((resolve) => { - core.application.applications$.pipe(first()).subscribe((apps) => { - resolve([...apps.values()]); - }); - }); - const availableApps = filterWorkspaceConfigurableApps(allApps); - this.workspaceConfigurableApps$.next(availableApps); + private getWorkspaceConfigurableApps$ = (core: CoreStart) => { + return core.application.applications$.pipe( + map((apps) => filterWorkspaceConfigurableApps([...apps.values()])) + ); }; /** @@ -248,7 +262,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> }; return renderApp(params, services, { - workspaceConfigurableApps$: this.workspaceConfigurableApps$, + registeredUseCases$: this.registeredUseCases$, }); }; @@ -356,11 +370,19 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> this.currentWorkspaceIdSubscription = this._changeSavedObjectCurrentWorkspace(); - this.setWorkspaceConfigurableApps(core).then(() => { - // filter the nav links based on the current workspace - this.filterNavLinks(core); + const useCaseStart = this.useCase.start({ + chrome: core.chrome, + workspaceConfigurableApps$: this.getWorkspaceConfigurableApps$(core), }); + this.registeredUseCasesUpdaterSubscription = useCaseStart + .getRegisteredUseCases$() + .subscribe((registeredUseCases) => { + this.registeredUseCases$.next(registeredUseCases); + }); + + this.filterNavLinks(core); + if (!core.chrome.navGroup.getNavGroupEnabled()) { this.addWorkspaceToBreadcrumbs(core); } @@ -374,5 +396,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> this.managementCurrentWorkspaceIdSubscription?.unsubscribe(); this.breadcrumbsSubscription?.unsubscribe(); this.unregisterNavGroupUpdater?.(); + this.registeredUseCasesUpdaterSubscription?.unsubscribe(); + this.workspaceAndUseCasesCombineSubscription?.unsubscribe(); } } diff --git a/src/plugins/workspace/public/services/use_case_service.test.ts b/src/plugins/workspace/public/services/use_case_service.test.ts new file mode 100644 index 000000000000..21049625d85e --- /dev/null +++ b/src/plugins/workspace/public/services/use_case_service.test.ts @@ -0,0 +1,120 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { BehaviorSubject } from 'rxjs'; +import { first } from 'rxjs/operators'; +import { chromeServiceMock } from '../../../../core/public/mocks'; +import { NavGroupType } from '../../../../core/public'; +import { UseCaseService } from './use_case_service'; + +const mockNavGroupsMap = { + system: { + id: 'system', + title: 'System', + navLinks: [], + type: NavGroupType.SYSTEM, + }, + search: { + id: 'search', + title: 'Search', + navLinks: [{ id: 'searchRelevance' }], + order: 2000, + }, + observability: { + id: 'observability', + title: 'Observability', + description: 'Observability description', + navLinks: [{ id: 'dashboards' }], + order: 1000, + }, +}; +const setupUseCaseStart = (options?: { navGroupEnabled?: boolean }) => { + const chrome = chromeServiceMock.createStartContract(); + const workspaceConfigurableApps$ = new BehaviorSubject([{ id: 'searchRelevance' }]); + const navGroupsMap$ = new BehaviorSubject(mockNavGroupsMap); + const useCase = new UseCaseService(); + + chrome.navGroup.getNavGroupEnabled.mockImplementation(() => options?.navGroupEnabled ?? true); + chrome.navGroup.getNavGroupsMap$.mockImplementation(() => navGroupsMap$); + + return { + chrome, + navGroupsMap$, + workspaceConfigurableApps$, + useCaseStart: useCase.start({ + chrome, + workspaceConfigurableApps$, + ...options, + }), + }; +}; + +describe('UseCaseService', () => { + describe('#start', () => { + it('should return built in use cases when nav group disabled', async () => { + const { useCaseStart } = setupUseCaseStart({ + navGroupEnabled: false, + }); + const useCases = await useCaseStart.getRegisteredUseCases$().pipe(first()).toPromise(); + + expect(useCases).toHaveLength(1); + expect(useCases).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: 'search', + title: 'Search', + features: expect.arrayContaining(['searchRelevance']), + }), + ]) + ); + }); + + it('should return registered use cases when nav group disabled', async () => { + const { useCaseStart } = setupUseCaseStart(); + const useCases = await useCaseStart.getRegisteredUseCases$().pipe(first()).toPromise(); + + expect(useCases).toEqual([ + expect.objectContaining({ + id: 'observability', + title: 'Observability', + features: expect.arrayContaining(['dashboards']), + }), + expect.objectContaining({ + id: 'search', + title: 'Search', + features: expect.arrayContaining(['searchRelevance']), + }), + expect.objectContaining({ + id: 'system', + title: 'System', + features: [], + systematic: true, + }), + ]); + }); + + it('should not emit after navGroupsMap$ emit same value', async () => { + const { useCaseStart, navGroupsMap$ } = setupUseCaseStart(); + const registeredUseCase$ = useCaseStart.getRegisteredUseCases$(); + const fn = jest.fn(); + + registeredUseCase$.subscribe(fn); + + expect(fn).toHaveBeenCalledTimes(1); + + navGroupsMap$.next({ ...mockNavGroupsMap }); + expect(fn).toHaveBeenCalledTimes(1); + + navGroupsMap$.next({ + ...mockNavGroupsMap, + observability: { + ...mockNavGroupsMap.observability, + navLinks: [{ id: 'bar' }], + }, + }); + expect(fn).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/src/plugins/workspace/public/services/use_case_service.ts b/src/plugins/workspace/public/services/use_case_service.ts new file mode 100644 index 000000000000..8c1adbf7d49c --- /dev/null +++ b/src/plugins/workspace/public/services/use_case_service.ts @@ -0,0 +1,73 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Observable } from 'rxjs'; +import { distinctUntilChanged, map } from 'rxjs/operators'; + +import { ChromeStart, PublicAppInfo } from '../../../../core/public'; +import { WORKSPACE_USE_CASES } from '../../common/constants'; +import { convertNavGroupToWorkspaceUseCase, isEqualWorkspaceUseCase } from '../utils'; + +export class UseCaseService { + constructor() {} + + start({ + chrome, + workspaceConfigurableApps$, + }: { + chrome: ChromeStart; + workspaceConfigurableApps$: Observable; + }) { + return { + getRegisteredUseCases$: () => { + if (chrome.navGroup.getNavGroupEnabled()) { + return chrome.navGroup + .getNavGroupsMap$() + .pipe( + map((navGroupsMap) => + Object.values(navGroupsMap).map(convertNavGroupToWorkspaceUseCase) + ) + ) + .pipe( + distinctUntilChanged((useCases, anotherUseCases) => { + return ( + useCases.length === anotherUseCases.length && + useCases.every( + (useCase) => + !!anotherUseCases.find((anotherUseCase) => + isEqualWorkspaceUseCase(useCase, anotherUseCase) + ) + ) + ); + }) + ) + .pipe( + map((useCases) => + useCases.sort( + (a, b) => + (a.order ?? Number.MAX_SAFE_INTEGER) - (b.order ?? Number.MAX_SAFE_INTEGER) + ) + ) + ); + } + + return workspaceConfigurableApps$.pipe( + map((configurableApps) => { + const configurableAppsId = configurableApps.map((app) => app.id); + + return [ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.analytics, + WORKSPACE_USE_CASES.search, + ].filter((useCase) => { + return useCase.features.some((featureId) => configurableAppsId.includes(featureId)); + }); + }) + ); + }, + }; + } +} diff --git a/src/plugins/workspace/public/types.ts b/src/plugins/workspace/public/types.ts index 9435685b9039..79fed7fa81ac 100644 --- a/src/plugins/workspace/public/types.ts +++ b/src/plugins/workspace/public/types.ts @@ -11,3 +11,12 @@ export type Services = CoreStart & { workspaceClient: WorkspaceClient; dataSourceManagement?: DataSourceManagementPluginSetup; }; + +export interface WorkspaceUseCase { + id: string; + title: string; + description: string; + features: string[]; + systematic?: boolean; + order?: number; +} diff --git a/src/plugins/workspace/public/utils.test.ts b/src/plugins/workspace/public/utils.test.ts index e3211990acf2..852324025100 100644 --- a/src/plugins/workspace/public/utils.test.ts +++ b/src/plugins/workspace/public/utils.test.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { AppNavLinkStatus, PublicAppInfo } from '../../../core/public'; +import { AppNavLinkStatus, NavGroupType, PublicAppInfo } from '../../../core/public'; import { featureMatchesConfig, filterWorkspaceConfigurableApps, @@ -11,15 +11,32 @@ import { isFeatureIdInsideUseCase, isNavGroupInFeatureConfigs, getDataSourcesList, + convertNavGroupToWorkspaceUseCase, + isEqualWorkspaceUseCase, } from './utils'; import { WorkspaceAvailability } from '../../../core/public'; import { coreMock } from '../../../core/public/mocks'; +import { WORKSPACE_USE_CASES } from '../common/constants'; const startMock = coreMock.createStart(); +const STATIC_USE_CASES = [ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.search, + WORKSPACE_USE_CASES.analytics, +]; +const useCaseMock = { + id: 'foo', + title: 'Foo', + description: 'Foo description', + features: ['bar'], + systematic: false, + order: 1, +}; describe('workspace utils: featureMatchesConfig', () => { it('feature configured with `*` should match any features', () => { - const match = featureMatchesConfig(['*']); + const match = featureMatchesConfig(['*'], STATIC_USE_CASES); expect(match({ id: 'dev_tools', category: { id: 'management', label: 'Management' } })).toBe( true ); @@ -29,28 +46,31 @@ describe('workspace utils: featureMatchesConfig', () => { }); it('should NOT match the config if feature id not matches', () => { - const match = featureMatchesConfig(['discover', 'dashboards', 'visualize']); + const match = featureMatchesConfig(['discover', 'dashboards', 'visualize'], STATIC_USE_CASES); expect(match({ id: 'dev_tools', category: { id: 'management', label: 'Management' } })).toBe( false ); }); it('should match the config if feature id matches', () => { - const match = featureMatchesConfig(['discover', 'dashboards', 'visualize']); + const match = featureMatchesConfig(['discover', 'dashboards', 'visualize'], STATIC_USE_CASES); expect( match({ id: 'discover', category: { id: 'opensearchDashboards', label: 'Library' } }) ).toBe(true); }); it('should match the config if feature category matches', () => { - const match = featureMatchesConfig(['discover', 'dashboards', '@management', 'visualize']); + const match = featureMatchesConfig( + ['discover', 'dashboards', '@management', 'visualize'], + STATIC_USE_CASES + ); expect(match({ id: 'dev_tools', category: { id: 'management', label: 'Management' } })).toBe( true ); }); it('should match any features but not the excluded feature id', () => { - const match = featureMatchesConfig(['*', '!discover']); + const match = featureMatchesConfig(['*', '!discover'], STATIC_USE_CASES); expect(match({ id: 'dev_tools', category: { id: 'management', label: 'Management' } })).toBe( true ); @@ -60,7 +80,7 @@ describe('workspace utils: featureMatchesConfig', () => { }); it('should match any features but not the excluded feature category', () => { - const match = featureMatchesConfig(['*', '!@management']); + const match = featureMatchesConfig(['*', '!@management'], STATIC_USE_CASES); expect(match({ id: 'dev_tools', category: { id: 'management', label: 'Management' } })).toBe( false ); @@ -73,7 +93,7 @@ describe('workspace utils: featureMatchesConfig', () => { }); it('should NOT match the excluded feature category', () => { - const match = featureMatchesConfig(['!@management']); + const match = featureMatchesConfig(['!@management'], STATIC_USE_CASES); expect(match({ id: 'dev_tools', category: { id: 'management', label: 'Management' } })).toBe( false ); @@ -83,7 +103,7 @@ describe('workspace utils: featureMatchesConfig', () => { }); it('should match features of a category but NOT the excluded feature', () => { - const match = featureMatchesConfig(['@management', '!dev_tools']); + const match = featureMatchesConfig(['@management', '!dev_tools'], STATIC_USE_CASES); expect(match({ id: 'dev_tools', category: { id: 'management', label: 'Management' } })).toBe( false ); @@ -94,7 +114,7 @@ describe('workspace utils: featureMatchesConfig', () => { it('a config presents later in the config array should override the previous config', () => { // though `dev_tools` is excluded, but this config will override by '@management' as dev_tools has category 'management' - const match = featureMatchesConfig(['!dev_tools', '@management']); + const match = featureMatchesConfig(['!dev_tools', '@management'], STATIC_USE_CASES); expect(match({ id: 'dev_tools', category: { id: 'management', label: 'Management' } })).toBe( true ); @@ -104,7 +124,10 @@ describe('workspace utils: featureMatchesConfig', () => { }); it('should match features include by any use cases', () => { - const match = featureMatchesConfig(['use-case-observability', 'use-case-analytics']); + const match = featureMatchesConfig( + ['use-case-observability', 'use-case-analytics'], + STATIC_USE_CASES + ); expect(match({ id: 'dashboards' })).toBe(true); expect(match({ id: 'observability-traces' })).toBe(true); expect(match({ id: 'alerting' })).toBe(true); @@ -117,7 +140,8 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { expect( isAppAccessibleInWorkspace( { id: 'any_app', title: 'Any app', mount: jest.fn() }, - { id: 'workspace_id', name: 'workspace name' } + { id: 'workspace_id', name: 'workspace name' }, + STATIC_USE_CASES ) ).toBe(true); }); @@ -126,7 +150,8 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { expect( isAppAccessibleInWorkspace( { id: 'dev_tools', title: 'Any app', mount: jest.fn() }, - { id: 'workspace_id', name: 'workspace name', features: ['dev_tools'] } + { id: 'workspace_id', name: 'workspace name', features: ['dev_tools'] }, + STATIC_USE_CASES ) ).toBe(true); }); @@ -135,7 +160,8 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { expect( isAppAccessibleInWorkspace( { id: 'dev_tools', title: 'Any app', mount: jest.fn() }, - { id: 'workspace_id', name: 'workspace name', features: [] } + { id: 'workspace_id', name: 'workspace name', features: [] }, + STATIC_USE_CASES ) ).toBe(false); }); @@ -149,7 +175,8 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { mount: jest.fn(), navLinkStatus: AppNavLinkStatus.hidden, }, - { id: 'workspace_id', name: 'workspace name', features: [] } + { id: 'workspace_id', name: 'workspace name', features: [] }, + STATIC_USE_CASES ) ).toBe(true); }); @@ -163,7 +190,8 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { mount: jest.fn(), chromeless: true, }, - { id: 'workspace_id', name: 'workspace name', features: [] } + { id: 'workspace_id', name: 'workspace name', features: [] }, + STATIC_USE_CASES ) ).toBe(true); }); @@ -177,7 +205,8 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { mount: jest.fn(), workspaceAvailability: WorkspaceAvailability.outsideWorkspace, }, - { id: 'workspace_id', name: 'workspace name', features: [] } + { id: 'workspace_id', name: 'workspace name', features: [] }, + STATIC_USE_CASES ) ).toBe(false); }); @@ -190,7 +219,8 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { mount: jest.fn(), workspaceAvailability: WorkspaceAvailability.insideWorkspace, }, - { id: 'workspace_id', name: 'workspace name', features: ['home'] } + { id: 'workspace_id', name: 'workspace name', features: ['home'] }, + STATIC_USE_CASES ) ).toBe(true); }); @@ -205,7 +235,8 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { // eslint-disable-next-line no-bitwise WorkspaceAvailability.insideWorkspace | WorkspaceAvailability.outsideWorkspace, }, - { id: 'workspace_id', name: 'workspace name', features: ['home'] } + { id: 'workspace_id', name: 'workspace name', features: ['home'] }, + STATIC_USE_CASES ) ).toBe(true); }); @@ -278,7 +309,31 @@ describe('workspace utils: filterWorkspaceConfigurableApps', () => { describe('workspace utils: isFeatureIdInsideUseCase', () => { it('should return false for invalid use case', () => { - expect(isFeatureIdInsideUseCase('discover', 'use-case-invalid')).toBe(false); + expect(isFeatureIdInsideUseCase('discover', 'use-case-invalid', [])).toBe(false); + }); + it('should return false if feature not in use case', () => { + expect( + isFeatureIdInsideUseCase('discover', 'use-case-foo', [ + { + id: 'foo', + title: 'Foo', + description: 'Foo description', + features: [], + }, + ]) + ).toBe(false); + }); + it('should return true if feature id exists in use case', () => { + expect( + isFeatureIdInsideUseCase('discover', 'use-case-foo', [ + { + id: 'foo', + title: 'Foo', + description: 'Foo description', + features: ['discover'], + }, + ]) + ).toBe(true); }); }); @@ -325,3 +380,104 @@ describe('workspace utils: getDataSourcesList', () => { expect(await getDataSourcesList(mockedSavedObjectClient, [])).toStrictEqual([]); }); }); + +describe('workspace utils: convertNavGroupToWorkspaceUseCase', () => { + it('should convert nav group to consistent workspace use case', () => { + expect( + convertNavGroupToWorkspaceUseCase({ + id: 'foo', + title: 'Foo', + description: 'Foo description', + navLinks: [{ id: 'bar' }], + }) + ).toEqual({ + id: 'foo', + title: 'Foo', + description: 'Foo description', + features: ['bar'], + systematic: false, + }); + + expect( + convertNavGroupToWorkspaceUseCase({ + id: 'foo', + title: 'Foo', + description: 'Foo description', + navLinks: [{ id: 'bar' }], + type: NavGroupType.SYSTEM, + }) + ).toEqual({ + id: 'foo', + title: 'Foo', + description: 'Foo description', + features: ['bar'], + systematic: true, + }); + }); +}); + +describe('workspace utils: isEqualWorkspaceUseCase', () => { + it('should return false when id not equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + id: 'foo1', + }) + ).toEqual(false); + }); + it('should return false when title not equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + title: 'Foo1', + }) + ).toEqual(false); + }); + it('should return false when description not equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + description: 'Foo description 1', + }) + ).toEqual(false); + }); + it('should return false when systematic not equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + systematic: true, + }) + ).toEqual(false); + }); + it('should return false when order not equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + order: 2, + }) + ).toEqual(false); + }); + it('should return false when features length not equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + features: [], + }) + ).toEqual(false); + }); + it('should return false when features content not equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + features: ['baz'], + }) + ).toEqual(false); + }); + it('should return true when all properties equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + }) + ).toEqual(true); + }); +}); diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index da9987b2aa1a..aeb46993b6c6 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { SavedObjectsStart } from '../../../core/public'; +import { NavGroupType, SavedObjectsStart, NavGroupItemInMap } from '../../../core/public'; import { App, AppCategory, @@ -13,7 +13,8 @@ import { WorkspaceObject, WorkspaceAvailability, } from '../../../core/public'; -import { DEFAULT_SELECTED_FEATURES_IDS, WORKSPACE_USE_CASES } from '../common/constants'; +import { DEFAULT_SELECTED_FEATURES_IDS } from '../common/constants'; +import { WorkspaceUseCase } from './types'; const USE_CASE_PREFIX = 'use-case-'; @@ -22,22 +23,21 @@ export const getUseCaseFeatureConfig = (useCaseId: string) => `${USE_CASE_PREFIX export const isUseCaseFeatureConfig = (featureConfig: string) => featureConfig.startsWith(USE_CASE_PREFIX); -type WorkspaceUseCaseId = keyof typeof WORKSPACE_USE_CASES; - export const getUseCaseFromFeatureConfig = (featureConfig: string) => { if (isUseCaseFeatureConfig(featureConfig)) { - const useCaseId = featureConfig.substring(USE_CASE_PREFIX.length); - if (Object.keys(WORKSPACE_USE_CASES).includes(useCaseId)) { - return useCaseId as WorkspaceUseCaseId; - } + return featureConfig.substring(USE_CASE_PREFIX.length); } return null; }; -export const isFeatureIdInsideUseCase = (featureId: string, featureConfig: string) => { - const useCase = getUseCaseFromFeatureConfig(featureConfig); - if (useCase && useCase in WORKSPACE_USE_CASES) { - return WORKSPACE_USE_CASES[useCase].features.includes(featureId); +export const isFeatureIdInsideUseCase = ( + featureId: string, + featureConfig: string, + useCases: WorkspaceUseCase[] +) => { + const useCase = useCases.find(({ id }) => id === getUseCaseFromFeatureConfig(featureConfig)); + if (useCase) { + return useCase.features.includes(featureId); } return false; }; @@ -58,7 +58,7 @@ export const isNavGroupInFeatureConfigs = (navGroupId: string, featureConfigs: s * 6. For feature id start with use case prefix, it will read use case's features and match every passed apps. * For example, ['user-case-observability'] matches all features under observability use case. */ -export const featureMatchesConfig = (featureConfigs: string[]) => ({ +export const featureMatchesConfig = (featureConfigs: string[], useCases: WorkspaceUseCase[]) => ({ id, category, }: { @@ -79,11 +79,8 @@ export const featureMatchesConfig = (featureConfigs: string[]) => ({ } // matches any feature inside use cases - if (getUseCaseFromFeatureConfig(featureConfig)) { - const isInsideUseCase = isFeatureIdInsideUseCase(id, featureConfig); - if (isInsideUseCase) { - matched = true; - } + if (isFeatureIdInsideUseCase(id, featureConfig, useCases)) { + matched = true; } // The config starts with `@` matches a category @@ -114,7 +111,11 @@ export const featureMatchesConfig = (featureConfigs: string[]) => ({ /** * Check if an app is accessible in a workspace based on the workspace configured features */ -export function isAppAccessibleInWorkspace(app: App, workspace: WorkspaceObject) { +export function isAppAccessibleInWorkspace( + app: App, + workspace: WorkspaceObject, + availableUseCases: WorkspaceUseCase[] +) { /** * App is not accessible within workspace if it explicitly declare itself as WorkspaceAvailability.outsideWorkspace */ @@ -132,7 +133,7 @@ export function isAppAccessibleInWorkspace(app: App, workspace: WorkspaceObject) /** * The app is configured into a workspace, it is accessible after entering the workspace */ - const featureMatcher = featureMatchesConfig(workspace.features); + const featureMatcher = featureMatchesConfig(workspace.features, availableUseCases); if (featureMatcher({ id: app.id, category: app.category })) { return true; } @@ -202,3 +203,44 @@ export const getDataSourcesList = (client: SavedObjectsStart['client'], workspac } }); }; + +export const convertNavGroupToWorkspaceUseCase = ({ + id, + title, + description, + navLinks, + type, + order, +}: NavGroupItemInMap): WorkspaceUseCase => ({ + id, + title, + description, + features: navLinks.map((item) => item.id), + systematic: type === NavGroupType.SYSTEM, + order, +}); + +export const isEqualWorkspaceUseCase = (a: WorkspaceUseCase, b: WorkspaceUseCase) => { + if (a.id !== b.id) { + return false; + } + if (a.title !== b.title) { + return false; + } + if (a.description !== b.description) { + return false; + } + if (a.systematic !== b.systematic) { + return false; + } + if (a.order !== b.order) { + return false; + } + if ( + a.features.length !== b.features.length || + a.features.some((featureId) => !b.features.includes(featureId)) + ) { + return false; + } + return true; +}; From 4b3bc4335e7206783ac91db1f762e50014743384 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:56:07 +0800 Subject: [PATCH 086/276] [Workspace] Recover data source management in workspace (#7296) (#7315) * recover DSM in workspace * Changeset file for PR #7296 created/updated --------- (cherry picked from commit 352682b162f689f6cc12a770f9d222612c3c4630) Signed-off-by: tygao Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: ZilongX <99905560+ZilongX@users.noreply.github.com> --- changelogs/fragments/7296.yml | 2 ++ src/plugins/workspace/public/plugin.ts | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/7296.yml diff --git a/changelogs/fragments/7296.yml b/changelogs/fragments/7296.yml new file mode 100644 index 000000000000..15b7ae679cce --- /dev/null +++ b/changelogs/fragments/7296.yml @@ -0,0 +1,2 @@ +feat: +- Recover data source management in workspace ([#7296](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7296)) \ No newline at end of file diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index ec67754cee3c..db496633128c 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -143,7 +143,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> }; /** - * If workspace is enabled and user has entered workspace, hide advance settings and dataSource menu by disabling the corresponding apps. + * If workspace is enabled and user has entered workspace, hide advance settings by disabling the corresponding apps. */ private disableManagementApps(core: CoreSetup, management: ManagementSetup) { const currentWorkspaceId$ = core.workspaces.currentWorkspaceId$; @@ -152,7 +152,7 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> this.managementCurrentWorkspaceIdSubscription = currentWorkspaceId$.subscribe( (currentWorkspaceId) => { if (currentWorkspaceId) { - ['settings', 'dataSources'].forEach((appId) => + ['settings'].forEach((appId) => management.sections.section.opensearchDashboards.getApp(appId)?.disable() ); } From 47e84edbee8b9ee67b60759f369d7433ca6f7107 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 10:51:56 +0800 Subject: [PATCH 087/276] [Workspace]Add "All use case" option to workspace form (#7318) (#7338) * Add all use case option * Changeset file for PR #7318 created/updated * Changeset file for PR #7318 created/updated * Changeset file for PR #7318 created/updated * Fix use case selection * All use case can accessible any app and add comment * Remove duplicate style import --------- (cherry picked from commit 5741fd7c262f4ace7d63dbc18c9549f8d35a92f7) Signed-off-by: Lin Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7318.yml | 2 + .../workspace_form/use_workspace_form.test.ts | 13 +++++++ .../workspace_form/use_workspace_form.ts | 21 +++++----- .../workspace_form/workspace_detail_form.tsx | 6 +-- .../workspace_form/workspace_form.tsx | 6 +-- .../workspace_use_case.test.tsx | 13 +++---- .../workspace_form/workspace_use_case.tsx | 28 ++++++------- .../components/workspace_list/index.test.tsx | 3 +- .../components/workspace_list/index.tsx | 23 +++++------ src/plugins/workspace/public/plugin.ts | 13 +++++++ src/plugins/workspace/public/utils.test.ts | 25 +++++++++--- src/plugins/workspace/public/utils.ts | 39 ++++++++++++++----- 12 files changed, 122 insertions(+), 70 deletions(-) create mode 100644 changelogs/fragments/7318.yml diff --git a/changelogs/fragments/7318.yml b/changelogs/fragments/7318.yml new file mode 100644 index 000000000000..4f7d9abe3553 --- /dev/null +++ b/changelogs/fragments/7318.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace]Add "All use case" option to workspace form ([#7318](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7318)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts index 2d5a5e00ce6f..ae9ba5d6a4fa 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts @@ -127,4 +127,17 @@ describe('useWorkspaceForm', () => { }) ); }); + it('should update selected use case', () => { + const { renderResult } = setup({ + id: 'foo', + name: 'test-workspace-name', + features: ['use-case-observability'], + }); + + expect(renderResult.result.current.formData.useCase).toBe('observability'); + act(() => { + renderResult.result.current.handleUseCaseChange('search'); + }); + expect(renderResult.result.current.formData.useCase).toBe('search'); + }); }); diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts index b15a6e6a670d..e0b01454fa0f 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts @@ -13,8 +13,8 @@ import { import { useApplications } from '../../hooks'; import { + getFirstUseCaseOfFeatureConfigs, getUseCaseFeatureConfig, - getUseCaseFromFeatureConfig, isUseCaseFeatureConfig, } from '../../utils'; import { DataSource } from '../../../common/types'; @@ -30,8 +30,6 @@ import { WorkspacePermissionItemType } from './constants'; const workspaceHtmlIdGenerator = htmlIdGenerator(); -const isNotNull = (value: T | null): value is T => !!value; - export const useWorkspaceForm = ({ application, defaultValues, @@ -51,10 +49,9 @@ export const useWorkspaceForm = ({ const [featureConfigs, setFeatureConfigs] = useState( appendDefaultFeatureIds(defaultValues?.features ?? []) ); - const selectedUseCases = useMemo( - () => featureConfigs.map(getUseCaseFromFeatureConfig).filter(isNotNull), - [featureConfigs] - ); + const selectedUseCase = useMemo(() => getFirstUseCaseOfFeatureConfigs(featureConfigs), [ + featureConfigs, + ]); const [permissionSettings, setPermissionSettings] = useState< Array & Partial> >(initialPermissionSettingsRef.current); @@ -72,7 +69,7 @@ export const useWorkspaceForm = ({ name, description, features: featureConfigs, - useCases: selectedUseCases, + useCase: selectedUseCase, color, permissionSettings, selectedDataSources, @@ -92,14 +89,14 @@ export const useWorkspaceForm = ({ formIdRef.current = workspaceHtmlIdGenerator(); } - const handleUseCasesChange = useCallback( - (newUseCases: string[]) => { + const handleUseCaseChange = useCallback( + (newUseCase: string) => { setFeatureConfigs((previousFeatureConfigs) => { return [ ...previousFeatureConfigs.filter( (featureConfig) => !isUseCaseFeatureConfig(featureConfig) ), - ...newUseCases.map((useCaseItem) => getUseCaseFeatureConfig(useCaseItem)), + getUseCaseFeatureConfig(newUseCase), ]; }); }, @@ -157,7 +154,7 @@ export const useWorkspaceForm = ({ numberOfChanges, handleFormSubmit, handleColorChange, - handleUseCasesChange, + handleUseCaseChange, handleNameInputChange, setPermissionSettings, setSelectedDataSources, diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx index 2e8b7cb32415..3834e7a23628 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx @@ -59,7 +59,7 @@ export const WorkspaceDetailForm = (props: WorkspaceFormProps) => { numberOfChanges, handleFormSubmit, handleColorChange, - handleUseCasesChange, + handleUseCaseChange, setPermissionSettings, handleNameInputChange, setSelectedDataSources, @@ -109,8 +109,8 @@ export const WorkspaceDetailForm = (props: WorkspaceFormProps) => { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index 07c86ef15ab0..c7e319b48435 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -41,7 +41,7 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { numberOfChanges, handleFormSubmit, handleColorChange, - handleUseCasesChange, + handleUseCaseChange, handleNameInputChange, setPermissionSettings, setSelectedDataSources, @@ -85,8 +85,8 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx index 7aa04a547c2c..9825cf07c209 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx @@ -23,11 +23,10 @@ const setup = (options?: Partial) => { id: 'system-use-case', title: 'System use case', description: 'System use case description', - features: [], systematic: true, }, ]} - value={[]} + value="" onChange={onChangeMock} formErrors={formErrors} {...options} @@ -49,19 +48,19 @@ describe('WorkspaceUseCase', () => { expect(renderResult.getByText('Search')).toBeInTheDocument(); }); - it('should call onChange with new added use case', () => { + it('should call onChange with new checked use case', () => { const { renderResult, onChangeMock } = setup(); expect(onChangeMock).not.toHaveBeenCalled(); fireEvent.click(renderResult.getByText('Observability')); - expect(onChangeMock).toHaveBeenLastCalledWith(['observability']); + expect(onChangeMock).toHaveBeenLastCalledWith('observability'); }); - it('should call onChange without removed use case', () => { - const { renderResult, onChangeMock } = setup({ value: ['observability'] }); + it('should not call onChange after checked use case clicked', () => { + const { renderResult, onChangeMock } = setup({ value: 'observability' }); expect(onChangeMock).not.toHaveBeenCalled(); fireEvent.click(renderResult.getByText('Observability')); - expect(onChangeMock).toHaveBeenLastCalledWith([]); + expect(onChangeMock).not.toHaveBeenCalled(); }); }); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx index 06a00cefa39b..e77f5b03c709 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx @@ -6,6 +6,8 @@ import React, { useCallback } from 'react'; import { i18n } from '@osd/i18n'; import { EuiCheckableCard, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiText } from '@elastic/eui'; + +import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; import { WorkspaceUseCase as WorkspaceUseCaseObject } from '../../types'; import { WorkspaceFormErrors } from './types'; import './workspace_use_case.scss'; @@ -31,7 +33,7 @@ const WorkspaceUseCaseCard = ({ return ( void; + value: string | undefined; + onChange: (newValue: string) => void; formErrors: WorkspaceFormErrors; - availableUseCases: WorkspaceUseCaseObject[]; + availableUseCases: Array< + Pick + >; } export const WorkspaceUseCase = ({ @@ -59,17 +63,6 @@ export const WorkspaceUseCase = ({ formErrors, availableUseCases, }: WorkspaceUseCaseProps) => { - const handleCardChange = useCallback( - (id: string) => { - if (!value.includes(id)) { - onChange([...value, id]); - return; - } - onChange(value.filter((item) => item !== id)); - }, - [value, onChange] - ); - return ( {availableUseCases .filter((item) => !item.systematic) + .concat(DEFAULT_NAV_GROUPS.all) .map(({ id, title, description }) => ( ))} diff --git a/src/plugins/workspace/public/components/workspace_list/index.test.tsx b/src/plugins/workspace/public/components/workspace_list/index.test.tsx index 5e55205c196e..d939b8f84ea4 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.test.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.test.tsx @@ -25,7 +25,7 @@ jest.mock('../delete_workspace_modal', () => ({ function getWrapWorkspaceListInContext( workspaceList = [ - { id: 'id1', name: 'name1', features: [] }, + { id: 'id1', name: 'name1', features: ['use-case-all'] }, { id: 'id2', name: 'name2' }, { id: 'id3', name: 'name3', features: ['use-case-observability'] }, ] @@ -69,6 +69,7 @@ describe('WorkspaceList', () => { expect(getByText('name2')).toBeInTheDocument(); // should display use case + expect(getByText('All use case')).toBeInTheDocument(); expect(getByText('Observability')).toBeInTheDocument(); }); it('should be able to apply debounce search after input', async () => { diff --git a/src/plugins/workspace/public/components/workspace_list/index.tsx b/src/plugins/workspace/public/components/workspace_list/index.tsx index 0d2e3c79082d..3a9342cf68f6 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.tsx @@ -17,7 +17,7 @@ import { import useObservable from 'react-use/lib/useObservable'; import { BehaviorSubject, of } from 'rxjs'; import { i18n } from '@osd/i18n'; -import { debounce } from '../../../../../core/public'; +import { debounce, DEFAULT_NAV_GROUPS } from '../../../../../core/public'; import { WorkspaceAttribute } from '../../../../../core/public'; import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public'; import { navigateToWorkspaceDetail } from '../utils/workspace'; @@ -26,7 +26,7 @@ import { WORKSPACE_CREATE_APP_ID } from '../../../common/constants'; import { cleanWorkspaceId } from '../../../../../core/public'; import { DeleteWorkspaceModal } from '../delete_workspace_modal'; -import { getUseCaseFromFeatureConfig } from '../../utils'; +import { getFirstUseCaseOfFeatureConfigs, getUseCaseFromFeatureConfig } from '../../utils'; import { WorkspaceUseCase } from '../../types'; const WORKSPACE_LIST_PAGE_DESCRIPTION = i18n.translate('workspace.list.description', { @@ -108,17 +108,14 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { if (!features || features.length === 0) { return ''; } - const results: string[] = []; - features.forEach((featureConfig) => { - const useCaseId = getUseCaseFromFeatureConfig(featureConfig); - if (useCaseId) { - const useCase = registeredUseCases?.find(({ id }) => id === useCaseId); - if (useCase) { - results.push(useCase.title); - } - } - }); - return results.join(', '); + const useCaseId = getFirstUseCaseOfFeatureConfigs(features); + const useCase = + useCaseId === DEFAULT_NAV_GROUPS.all.id + ? DEFAULT_NAV_GROUPS.all + : registeredUseCases?.find(({ id }) => id === useCaseId); + if (useCase) { + return useCase.title; + } }, }, { diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index db496633128c..a2c84554205a 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -21,6 +21,7 @@ import { NavGroupStatus, DEFAULT_NAV_GROUPS, NavGroupType, + ALL_USE_CASE_ID, } from '../../../core/public'; import { WORKSPACE_FATAL_ERROR_APP_ID, @@ -38,6 +39,7 @@ import { getWorkspaceColumn } from './components/workspace_column'; import { DataSourceManagementPluginSetup } from '../../../plugins/data_source_management/public'; import { filterWorkspaceConfigurableApps, + getFirstUseCaseOfFeatureConfigs, isAppAccessibleInWorkspace, isNavGroupInFeatureConfigs, } from './utils'; @@ -119,9 +121,20 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> this.currentWorkspaceSubscription = currentWorkspace$.subscribe((currentWorkspace) => { if (currentWorkspace) { this.navGroupUpdater$.next((navGroup) => { + /** + * The following logic determines whether a navigation group should be hidden or not based on the workspace's feature configurations. + * It checks the following conditions: + * 1. The navigation group is not a system-level group (system groups are always visible). + * 2. The current workspace has feature configurations set up. + * 3. The current workspace's use case it not "All use case". + * 4. The current navigation group is not included in the feature configurations of the workspace. + * + * If all these conditions are true, it means that the navigation group should be hidden. + */ if ( navGroup.type !== NavGroupType.SYSTEM && currentWorkspace.features && + getFirstUseCaseOfFeatureConfigs(currentWorkspace.features) !== ALL_USE_CASE_ID && !isNavGroupInFeatureConfigs(navGroup.id, currentWorkspace.features) ) { return { diff --git a/src/plugins/workspace/public/utils.test.ts b/src/plugins/workspace/public/utils.test.ts index 852324025100..4763a4455746 100644 --- a/src/plugins/workspace/public/utils.test.ts +++ b/src/plugins/workspace/public/utils.test.ts @@ -125,12 +125,18 @@ describe('workspace utils: featureMatchesConfig', () => { it('should match features include by any use cases', () => { const match = featureMatchesConfig( - ['use-case-observability', 'use-case-analytics'], + ['use-case-observability', 'use-case-search'], STATIC_USE_CASES ); expect(match({ id: 'dashboards' })).toBe(true); expect(match({ id: 'observability-traces' })).toBe(true); - expect(match({ id: 'alerting' })).toBe(true); + + /** + * The searchRelevance is a feature under search use case. Since each workspace only can be a specific use case, + * the feature matches will use first use case to check if features exists. The observability doesn't have + * searchRelevance feature, it will return false. + */ + expect(match({ id: 'searchRelevance' })).toBe(false); expect(match({ id: 'not-in-any-use-case' })).toBe(false); }); }); @@ -240,6 +246,15 @@ describe('workspace utils: isAppAccessibleInWorkspace', () => { ) ).toBe(true); }); + it('any app is accessible when workspace is all use case', () => { + expect( + isAppAccessibleInWorkspace( + { id: 'any_app', title: 'Any app', mount: jest.fn() }, + { id: 'workspace_id', name: 'workspace name', features: ['use-case-all'] }, + STATIC_USE_CASES + ) + ).toBe(true); + }); }); describe('workspace utils: filterWorkspaceConfigurableApps', () => { @@ -309,11 +324,11 @@ describe('workspace utils: filterWorkspaceConfigurableApps', () => { describe('workspace utils: isFeatureIdInsideUseCase', () => { it('should return false for invalid use case', () => { - expect(isFeatureIdInsideUseCase('discover', 'use-case-invalid', [])).toBe(false); + expect(isFeatureIdInsideUseCase('discover', 'invalid', [])).toBe(false); }); it('should return false if feature not in use case', () => { expect( - isFeatureIdInsideUseCase('discover', 'use-case-foo', [ + isFeatureIdInsideUseCase('discover', 'foo', [ { id: 'foo', title: 'Foo', @@ -325,7 +340,7 @@ describe('workspace utils: isFeatureIdInsideUseCase', () => { }); it('should return true if feature id exists in use case', () => { expect( - isFeatureIdInsideUseCase('discover', 'use-case-foo', [ + isFeatureIdInsideUseCase('discover', 'foo', [ { id: 'foo', title: 'Foo', diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index aeb46993b6c6..589f1d8159d2 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -3,7 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { NavGroupType, SavedObjectsStart, NavGroupItemInMap } from '../../../core/public'; +import { + NavGroupType, + SavedObjectsStart, + NavGroupItemInMap, + ALL_USE_CASE_ID, +} from '../../../core/public'; import { App, AppCategory, @@ -32,14 +37,11 @@ export const getUseCaseFromFeatureConfig = (featureConfig: string) => { export const isFeatureIdInsideUseCase = ( featureId: string, - featureConfig: string, + useCaseId: string, useCases: WorkspaceUseCase[] ) => { - const useCase = useCases.find(({ id }) => id === getUseCaseFromFeatureConfig(featureConfig)); - if (useCase) { - return useCase.features.includes(featureId); - } - return false; + const availableFeatures = useCases.find(({ id }) => id === useCaseId)?.features ?? []; + return availableFeatures.includes(featureId); }; export const isNavGroupInFeatureConfigs = (navGroupId: string, featureConfigs: string[]) => @@ -66,6 +68,7 @@ export const featureMatchesConfig = (featureConfigs: string[], useCases: Workspa category?: AppCategory; }) => { let matched = false; + let firstUseCaseId: string | undefined; /** * Iterate through each feature configuration to determine if the given feature matches any of them. @@ -79,8 +82,14 @@ export const featureMatchesConfig = (featureConfigs: string[], useCases: Workspa } // matches any feature inside use cases - if (isFeatureIdInsideUseCase(id, featureConfig, useCases)) { - matched = true; + if (!firstUseCaseId) { + const useCaseId = getUseCaseFromFeatureConfig(featureConfig); + if (useCaseId) { + firstUseCaseId = useCaseId; + if (isFeatureIdInsideUseCase(id, firstUseCaseId, useCases)) { + matched = true; + } + } } // The config starts with `@` matches a category @@ -130,6 +139,13 @@ export function isAppAccessibleInWorkspace( return true; } + /** + * When workspace is all use case, all apps are accessible + */ + if (getFirstUseCaseOfFeatureConfigs(workspace.features) === ALL_USE_CASE_ID) { + return true; + } + /** * The app is configured into a workspace, it is accessible after entering the workspace */ @@ -244,3 +260,8 @@ export const isEqualWorkspaceUseCase = (a: WorkspaceUseCase, b: WorkspaceUseCase } return true; }; + +const isNotNull = (value: T | null): value is T => !!value; + +export const getFirstUseCaseOfFeatureConfigs = (featureConfigs: string[]): string | undefined => + featureConfigs.map(getUseCaseFromFeatureConfig).filter(isNotNull)[0]; From 4ed0c2e33cae20d12fa18c72907fa3510b8a71c5 Mon Sep 17 00:00:00 2001 From: yuboluo Date: Sun, 21 Jul 2024 12:11:44 +0800 Subject: [PATCH 088/276] [Workspace] Refactor the UI of workspace picker (#7342) Signed-off-by: yubonluo --- changelogs/fragments/7045.yml | 2 + src/core/public/chrome/index.ts | 6 +- .../public/chrome/recently_accessed/index.ts | 2 + src/core/public/index.ts | 2 + src/plugins/workspace/common/constants.ts | 2 + .../workspace_menu/workspace_menu.test.tsx | 159 +++++--- .../workspace_menu/workspace_menu.tsx | 373 +++++++++++------- src/plugins/workspace/public/plugin.test.ts | 17 +- src/plugins/workspace/public/plugin.ts | 27 +- .../public/recent_workspace_manager.test.ts | 33 ++ .../public/recent_workspace_manager.ts | 51 +++ 11 files changed, 471 insertions(+), 203 deletions(-) create mode 100644 changelogs/fragments/7045.yml create mode 100644 src/plugins/workspace/public/recent_workspace_manager.test.ts create mode 100644 src/plugins/workspace/public/recent_workspace_manager.ts diff --git a/changelogs/fragments/7045.yml b/changelogs/fragments/7045.yml new file mode 100644 index 000000000000..5e1d9e73addb --- /dev/null +++ b/changelogs/fragments/7045.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace] Refactor the UI of workspace picker ([#7045](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7045)) \ No newline at end of file diff --git a/src/core/public/chrome/index.ts b/src/core/public/chrome/index.ts index f49e0e7efe80..02100ce4f63a 100644 --- a/src/core/public/chrome/index.ts +++ b/src/core/public/chrome/index.ts @@ -46,7 +46,11 @@ export { } from './ui/header/header_help_menu'; export { NavType, RightNavigationButton, RightNavigationButtonProps } from './ui'; export { ChromeNavLink, ChromeNavLinks, ChromeNavLinkUpdateableFields } from './nav_links'; -export { ChromeRecentlyAccessed, ChromeRecentlyAccessedHistoryItem } from './recently_accessed'; +export { + ChromeRecentlyAccessed, + ChromeRecentlyAccessedHistoryItem, + PersistedLog, +} from './recently_accessed'; export { ChromeNavControl, ChromeNavControls } from './nav_controls'; export { ChromeDocTitle } from './doc_title'; export { RightNavigationOrder } from './constants'; diff --git a/src/core/public/chrome/recently_accessed/index.ts b/src/core/public/chrome/recently_accessed/index.ts index 8bb2e306b221..9fb34b520470 100644 --- a/src/core/public/chrome/recently_accessed/index.ts +++ b/src/core/public/chrome/recently_accessed/index.ts @@ -33,3 +33,5 @@ export { ChromeRecentlyAccessedHistoryItem, RecentlyAccessedService, } from './recently_accessed_service'; + +export { PersistedLog } from './persisted_log'; diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 59da446d1fe9..8c387361a9ca 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -73,6 +73,7 @@ import { RightNavigationButtonProps, ChromeRegistrationNavLink, ChromeNavGroupUpdater, + PersistedLog, NavGroupItemInMap, fulfillRegistrationLinksToChromeNavLinks, } from './chrome'; @@ -375,6 +376,7 @@ export { RightNavigationButtonProps, ChromeRegistrationNavLink, ChromeNavGroupUpdater, + PersistedLog, NavGroupItemInMap, fulfillRegistrationLinksToChromeNavLinks, }; diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index bdf9aa8ddfc5..9fef78152d8d 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -182,4 +182,6 @@ export const WORKSPACE_USE_CASES = Object.freeze({ }, }); +export const MAX_WORKSPACE_PICKER_NUM = 3; +export const RECENT_WORKSPACES_KEY = 'recentWorkspaces'; export const CURRENT_USER_PLACEHOLDER = '%me%'; diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx index 85ee89482724..d3578498c858 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx @@ -9,18 +9,51 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { WorkspaceMenu } from './workspace_menu'; import { coreMock } from '../../../../../core/public/mocks'; import { CoreStart } from '../../../../../core/public'; +import { BehaviorSubject, of } from 'rxjs'; +import { IntlProvider } from 'react-intl'; +import { recentWorkspaceManager } from '../../recent_workspace_manager'; +import { WORKSPACE_USE_CASES } from '../../../common/constants'; +import * as workspaceUtils from '../utils/workspace'; describe('', () => { let coreStartMock: CoreStart; + const navigateToApp = jest.fn(); + const registeredUseCases$ = new BehaviorSubject([ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.analytics, + WORKSPACE_USE_CASES.search, + ]); beforeEach(() => { coreStartMock = coreMock.createStart(); + coreStartMock.application.capabilities = { + navLinks: {}, + management: {}, + catalogue: {}, + savedObjectsManagement: {}, + workspaces: { permissionEnabled: true }, + dashboards: { isDashboardAdmin: true }, + }; + coreStartMock.application = { + ...coreStartMock.application, + navigateToApp, + }; + coreStartMock.workspaces.initialized$.next(true); jest.spyOn(coreStartMock.application, 'getUrlForApp').mockImplementation((appId: string) => { return `https://test.com/app/${appId}`; }); }); + const WorkspaceMenuCreatorComponent = () => { + return ( + + + + ); + }; + afterEach(() => { jest.clearAllMocks(); jest.restoreAllMocks(); @@ -28,38 +61,69 @@ describe('', () => { it('should display a list of workspaces in the dropdown', () => { coreStartMock.workspaces.workspaceList$.next([ - { id: 'workspace-1', name: 'workspace 1' }, - { id: 'workspace-2', name: 'workspace 2' }, + { id: 'workspace-1', name: 'workspace 1', features: [] }, + { id: 'workspace-2', name: 'workspace 2', features: [] }, + ]); + + render(); + const selectButton = screen.getByTestId('workspace-select-button'); + fireEvent.click(selectButton); + + expect(screen.getByText(/all workspaces/i)).toBeInTheDocument(); + expect(screen.getByTestId('workspace-menu-item-all-workspace-1')).toBeInTheDocument(); + expect(screen.getByTestId('workspace-menu-item-all-workspace-2')).toBeInTheDocument(); + }); + + it('should display a list of recent workspaces in the dropdown', () => { + jest.spyOn(recentWorkspaceManager, 'getRecentWorkspaces').mockReturnValue([ + { id: 'workspace-1', timestamp: 1234567890 }, + { id: 'workspace-2', timestamp: 1234567899 }, + ]); + + coreStartMock.workspaces.workspaceList$.next([ + { id: 'workspace-1', name: 'workspace 1', features: [] }, + { id: 'workspace-2', name: 'workspace 2', features: [] }, ]); - render(); - fireEvent.click(screen.getByText(/select a workspace/i)); + render(); + + const selectButton = screen.getByTestId('workspace-select-button'); + fireEvent.click(selectButton); - expect(screen.getByText(/workspace 1/i)).toBeInTheDocument(); - expect(screen.getByText(/workspace 2/i)).toBeInTheDocument(); + expect(screen.getByText(/recent workspaces/i)).toBeInTheDocument(); + expect(screen.getByTestId('workspace-menu-item-recent-workspace-1')).toBeInTheDocument(); + expect(screen.getByTestId('workspace-menu-item-recent-workspace-2')).toBeInTheDocument(); }); - it('should display current workspace name', () => { - coreStartMock.workspaces.currentWorkspace$.next({ id: 'workspace-1', name: 'workspace 1' }); - render(); - expect(screen.getByText(/workspace 1/i)).toBeInTheDocument(); + it('should display current workspace name and use case name', () => { + coreStartMock.workspaces.currentWorkspace$.next({ + id: 'workspace-1', + name: 'workspace 1', + features: ['use-case-observability'], + }); + render(); + + fireEvent.click(screen.getByTestId('current-workspace-button')); + expect(screen.getByTestId('workspace-menu-current-workspace-name')).toBeInTheDocument(); + expect(screen.getByTestId('workspace-menu-current-use-case')).toBeInTheDocument(); + expect(screen.getByText('Observability')).toBeInTheDocument(); }); it('should close the workspace dropdown list', async () => { - render(); - fireEvent.click(screen.getByText(/select a workspace/i)); + render(); + + fireEvent.click(screen.getByTestId('workspace-select-button')); - expect(screen.getByLabelText(/close workspace dropdown/i)).toBeInTheDocument(); - fireEvent.click(screen.getByLabelText(/close workspace dropdown/i)); + expect(screen.getByText(/all workspaces/i)).toBeInTheDocument(); + fireEvent.click(screen.getByTestId('workspace-select-button')); await waitFor(() => { - expect(screen.queryByLabelText(/close workspace dropdown/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/all workspaces/i)).not.toBeInTheDocument(); }); }); it('should navigate to the workspace', () => { coreStartMock.workspaces.workspaceList$.next([ - { id: 'workspace-1', name: 'workspace 1' }, - { id: 'workspace-2', name: 'workspace 2' }, + { id: 'workspace-1', name: 'workspace 1', features: ['use-case-observability'] }, ]); const originalLocation = window.location; @@ -69,12 +133,12 @@ describe('', () => { }, }); - render(); - fireEvent.click(screen.getByText(/select a workspace/i)); + render(); + fireEvent.click(screen.getByTestId('workspace-select-button')); fireEvent.click(screen.getByText(/workspace 1/i)); expect(window.location.assign).toHaveBeenCalledWith( - 'https://test.com/w/workspace-1/app/workspace_detail' + 'https://test.com/w/workspace-1/app/discover' ); Object.defineProperty(window, 'location', { @@ -82,39 +146,40 @@ describe('', () => { }); }); - it('should navigate to create workspace page', () => { - const originalLocation = window.location; - Object.defineProperty(window, 'location', { - value: { - assign: jest.fn(), - }, + it('should navigate to workspace management page', () => { + coreStartMock.workspaces.currentWorkspace$.next({ + id: 'workspace-1', + name: 'workspace 1', + features: ['use-case-observability'], }); + const navigateToWorkspaceDetail = jest.spyOn(workspaceUtils, 'navigateToWorkspaceDetail'); + render(); - render(); - fireEvent.click(screen.getByText(/select a workspace/i)); - fireEvent.click(screen.getByText(/create workspace/i)); - expect(window.location.assign).toHaveBeenCalledWith('https://test.com/app/workspace_create'); + fireEvent.click(screen.getByTestId('current-workspace-button')); + const button = screen.getByText(/Manage workspace/i); + fireEvent.click(button); + expect(navigateToWorkspaceDetail).toBeCalled(); + }); - Object.defineProperty(window, 'location', { - value: originalLocation, - }); + it('should navigate to workspaces management page', () => { + render(); + fireEvent.click(screen.getByTestId('workspace-select-button')); + fireEvent.click(screen.getByText(/manage workspaces/i)); + expect(coreStartMock.application.navigateToApp).toHaveBeenCalledWith('workspace_list'); }); - it('should navigate to workspace list page', () => { - const originalLocation = window.location; - Object.defineProperty(window, 'location', { - value: { - assign: jest.fn(), - }, - }); + it('should navigate to create workspace page', () => { + render(); + fireEvent.click(screen.getByTestId('workspace-select-button')); + fireEvent.click(screen.getByText(/create workspace/i)); + expect(coreStartMock.application.navigateToApp).toHaveBeenCalledWith('workspace_create'); + }); - render(); - fireEvent.click(screen.getByText(/select a workspace/i)); - fireEvent.click(screen.getByText(/all workspace/i)); - expect(window.location.assign).toHaveBeenCalledWith('https://test.com/app/workspace_list'); + it('should navigate to workspace list page', () => { + render(); - Object.defineProperty(window, 'location', { - value: originalLocation, - }); + fireEvent.click(screen.getByTestId('workspace-select-button')); + fireEvent.click(screen.getByText(/View all/i)); + expect(coreStartMock.application.navigateToApp).toHaveBeenCalledWith('workspace_list'); }); }); diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx index 986711a8b3d6..bda11fb3d113 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx @@ -4,61 +4,96 @@ */ import { i18n } from '@osd/i18n'; -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { useObservable } from 'react-use'; import { - EuiButtonIcon, - EuiContextMenu, - EuiFlexGroup, + EuiText, + EuiPanel, + EuiTitle, + EuiAvatar, + EuiButton, + EuiPopover, + EuiToolTip, EuiFlexItem, - EuiIcon, + EuiFlexGroup, EuiListGroup, + EuiButtonIcon, + EuiButtonEmpty, EuiListGroupItem, - EuiPopover, - EuiText, } from '@elastic/eui'; -import type { EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; - +import { BehaviorSubject } from 'rxjs'; import { WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID, + MAX_WORKSPACE_PICKER_NUM, WORKSPACE_DETAIL_APP_ID, } from '../../../common/constants'; -import { cleanWorkspaceId, formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; +import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; import { CoreStart, WorkspaceObject } from '../../../../../core/public'; +import { getFirstUseCaseOfFeatureConfigs } from '../../utils'; +import { recentWorkspaceManager } from '../../recent_workspace_manager'; +import { WorkspaceUseCase } from '../../types'; +import { navigateToWorkspaceDetail } from '../utils/workspace'; + +const defaultHeaderName = i18n.translate('workspace.menu.defaultHeaderName', { + defaultMessage: 'Workspaces', +}); + +const allWorkspacesTitle = i18n.translate('workspace.menu.title.allWorkspaces', { + defaultMessage: 'All workspaces', +}); + +const recentWorkspacesTitle = i18n.translate('workspace.menu.title.recentWorkspaces', { + defaultMessage: 'recent workspaces', +}); + +const createWorkspaceButton = i18n.translate('workspace.menu.button.createWorkspace', { + defaultMessage: 'Create workspace', +}); + +const viewAllButton = i18n.translate('workspace.menu.button.viewAll', { + defaultMessage: 'View all', +}); + +const manageWorkspaceButton = i18n.translate('workspace.menu.button.manageWorkspace', { + defaultMessage: 'Manage workspace', +}); + +const manageWorkspacesButton = i18n.translate('workspace.menu.button.manageWorkspaces', { + defaultMessage: 'Manage workspaces', +}); interface Props { coreStart: CoreStart; + registeredUseCases$: BehaviorSubject; } -/** - * Return maximum five workspaces, the current selected workspace - * will be on the top of the list. - */ -function getFilteredWorkspaceList( - workspaceList: WorkspaceObject[], - currentWorkspace: WorkspaceObject | null -): WorkspaceObject[] { - return [ - ...(currentWorkspace ? [currentWorkspace] : []), - ...workspaceList.filter((workspace) => workspace.id !== currentWorkspace?.id), - ].slice(0, 5); -} - -export const WorkspaceMenu = ({ coreStart }: Props) => { +export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { const [isPopoverOpen, setPopover] = useState(false); const currentWorkspace = useObservable(coreStart.workspaces.currentWorkspace$, null); const workspaceList = useObservable(coreStart.workspaces.workspaceList$, []); + const isDashboardAdmin = !!coreStart.application.capabilities.dashboards; + const availableUseCases = useObservable(registeredUseCases$, []); + + const filteredWorkspaceList = useMemo(() => { + return workspaceList.slice(0, MAX_WORKSPACE_PICKER_NUM); + }, [workspaceList]); + + const filteredRecentWorkspaces = useMemo(() => { + return recentWorkspaceManager + .getRecentWorkspaces() + .map((workspace) => workspaceList.find((ws) => ws.id === workspace.id)) + .filter((workspace): workspace is WorkspaceObject => workspace !== undefined) + .slice(0, MAX_WORKSPACE_PICKER_NUM); + }, [workspaceList]); - const defaultHeaderName = i18n.translate( - 'core.ui.primaryNav.workspacePickerMenu.defaultHeaderName', - { - defaultMessage: 'Select a workspace', - } - ); - const filteredWorkspaceList = getFilteredWorkspaceList(workspaceList, currentWorkspace); const currentWorkspaceName = currentWorkspace?.name ?? defaultHeaderName; + const getUseCase = (workspace: WorkspaceObject) => { + const useCaseId = getFirstUseCaseOfFeatureConfigs(workspace?.features!); + return availableUseCases.find((useCase) => useCase.id === useCaseId); + }; + const openPopover = () => { setPopover(!isPopoverOpen); }; @@ -67,113 +102,78 @@ export const WorkspaceMenu = ({ coreStart }: Props) => { setPopover(false); }; - const workspaceToItem = (workspace: WorkspaceObject) => { - const workspaceURL = formatUrlWithWorkspaceId( - coreStart.application.getUrlForApp(WORKSPACE_DETAIL_APP_ID, { - absolute: false, - }), - workspace.id, - coreStart.http.basePath - ); - const name = - currentWorkspace?.name === workspace.name ? ( - - {workspace.name} - - ) : ( - workspace.name - ); - return { - name, - key: workspace.id, - icon: , - onClick: () => { - window.location.assign(workspaceURL); - }, - }; - }; - - const getWorkspaceListItems = () => { - const workspaceListItems: EuiContextMenuPanelItemDescriptor[] = filteredWorkspaceList.map( - workspaceToItem - ); - workspaceListItems.push({ - icon: , - name: i18n.translate('core.ui.primaryNav.workspaceContextMenu.createWorkspace', { - defaultMessage: 'Create workspace', - }), - key: WORKSPACE_CREATE_APP_ID, - onClick: () => { - window.location.assign( - cleanWorkspaceId( - coreStart.application.getUrlForApp(WORKSPACE_CREATE_APP_ID, { - absolute: false, - }) - ) - ); - }, - }); - workspaceListItems.push({ - icon: , - name: i18n.translate('core.ui.primaryNav.workspaceContextMenu.allWorkspace', { - defaultMessage: 'All workspaces', - }), - key: WORKSPACE_LIST_APP_ID, - onClick: () => { - window.location.assign( - cleanWorkspaceId( - coreStart.application.getUrlForApp(WORKSPACE_LIST_APP_ID, { - absolute: false, - }) - ) - ); - }, - }); - return workspaceListItems; - }; + const currentWorkspaceButton = currentWorkspace ? ( + + + + ) : ( + + ); - const currentWorkspaceButton = ( - <> - + const getWorkspaceListGroup = (filterWorkspaceList: WorkspaceObject[], itemType: string) => { + const listItems = filterWorkspaceList.map((workspace: WorkspaceObject) => { + const appId = getUseCase(workspace)?.features[0] ?? WORKSPACE_DETAIL_APP_ID; + const useCaseURL = formatUrlWithWorkspaceId( + coreStart.application.getUrlForApp(appId, { + absolute: false, + }), + workspace.id, + coreStart.http.basePath + ); + return ( + } + label={ + + + {workspace.name} + + + } + onClick={() => { + window.location.assign(useCaseURL); }} /> - - - ); - - const currentWorkspaceTitle = ( - - - {currentWorkspaceName} - - - - - - ); - - const panels = [ - { - id: 0, - title: currentWorkspaceTitle, - items: getWorkspaceListItems(), - }, - ]; + ); + }); + return ( + <> + +

{itemType === 'all' ? allWorkspacesTitle : recentWorkspacesTitle}

+
+ + {listItems} + + + ); + }; return ( { panelPaddingSize="none" anchorPosition="downCenter" > - + + + {currentWorkspace ? ( + <> + + + + + + + {currentWorkspaceName} + + + + + {getUseCase(currentWorkspace)?.title ?? ''} + + + { + navigateToWorkspaceDetail(coreStart, currentWorkspace.id); + }} + > + {manageWorkspaceButton} + + + + ) : ( + <> + + + + + {currentWorkspaceName} + + + { + coreStart.application.navigateToApp(WORKSPACE_LIST_APP_ID); + }} + > + {manageWorkspacesButton} + + + + )} + + + + {getWorkspaceListGroup(filteredRecentWorkspaces, 'recent')} + {getWorkspaceListGroup(filteredWorkspaceList, 'all')} + + + + + { + coreStart.application.navigateToApp(WORKSPACE_LIST_APP_ID); + }} + > + {viewAllButton} + + + {isDashboardAdmin && ( + + { + coreStart.application.navigateToApp(WORKSPACE_CREATE_APP_ID); + }} + > + {createWorkspaceButton} + + + )} + + ); }; diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index b732280b92c8..fccd5745421f 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -148,15 +148,6 @@ describe('Workspace plugin', () => { windowSpy.mockRestore(); }); - it('#setup register workspace dropdown menu when setup', async () => { - const setupMock = coreMock.createSetup(); - const workspacePlugin = new WorkspacePlugin(); - await workspacePlugin.setup(setupMock, { - management: managementPluginMock.createSetupContract(), - }); - expect(setupMock.chrome.registerCollapsibleNavHeader).toBeCalledTimes(1); - }); - it('#setup should register workspace list with a visible application and register to settingsAndSetup nav group', async () => { const setupMock = coreMock.createSetup(); setupMock.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); @@ -240,6 +231,14 @@ describe('Workspace plugin', () => { }); }); + it('#start register workspace dropdown menu at left navigation bottom when start', async () => { + const coreStart = coreMock.createStart(); + coreStart.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); + const workspacePlugin = new WorkspacePlugin(); + workspacePlugin.start(coreStart); + + expect(coreStart.chrome.navControls.registerLeftBottom).toBeCalledTimes(1); + }); it('#start should not update systematic use case features after currentWorkspace set', async () => { const registeredUseCases$ = new BehaviorSubject([ { diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index a2c84554205a..104db7d9b91f 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -43,6 +43,8 @@ import { isAppAccessibleInWorkspace, isNavGroupInFeatureConfigs, } from './utils'; +import { recentWorkspaceManager } from './recent_workspace_manager'; +import { toMountPoint } from '../../opensearch_dashboards_react/public'; import { UseCaseService } from './services/use_case_service'; type WorkspaceAppType = ( @@ -262,6 +264,8 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> } currentAppIdSubscription.unsubscribe(); }); + // Add workspace id to recent workspaces. + recentWorkspaceManager.addRecentWorkspace(workspaceId); })(); } } @@ -319,16 +323,6 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> }, }); - /** - * Register workspace dropdown selector on the top of left navigation menu - */ - core.chrome.registerCollapsibleNavHeader(() => { - if (!this.coreStart) { - return null; - } - return React.createElement(WorkspaceMenu, { coreStart: this.coreStart }); - }); - // workspace list core.application.register({ id: WORKSPACE_LIST_APP_ID, @@ -398,6 +392,19 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> if (!core.chrome.navGroup.getNavGroupEnabled()) { this.addWorkspaceToBreadcrumbs(core); + } else { + /** + * Register workspace dropdown selector on the left navigation bottom + */ + core.chrome.navControls.registerLeftBottom({ + order: 2, + mount: toMountPoint( + React.createElement(WorkspaceMenu, { + coreStart: core, + registeredUseCases$: this.registeredUseCases$, + }) + ), + }); } return {}; diff --git a/src/plugins/workspace/public/recent_workspace_manager.test.ts b/src/plugins/workspace/public/recent_workspace_manager.test.ts new file mode 100644 index 000000000000..16ea6291faef --- /dev/null +++ b/src/plugins/workspace/public/recent_workspace_manager.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { RecentWorkspaceManager } from './recent_workspace_manager'; + +describe('RecentWorkspaceManager', () => { + let recentWorkspaceManager: RecentWorkspaceManager; + + beforeEach(() => { + recentWorkspaceManager = RecentWorkspaceManager.getInstance(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should be a singleton', () => { + const anotherInstance = RecentWorkspaceManager.getInstance(); + expect(recentWorkspaceManager).toBe(anotherInstance); + }); + + it('should add and get recent workspaces', () => { + recentWorkspaceManager.addRecentWorkspace('workspace1'); + recentWorkspaceManager.addRecentWorkspace('workspace2'); + + const recentWorkspaces = recentWorkspaceManager.getRecentWorkspaces(); + expect(recentWorkspaces.length).toEqual(2); + expect(recentWorkspaces[0].id).toEqual('workspace2'); + expect(recentWorkspaces[1].id).toEqual('workspace1'); + }); +}); diff --git a/src/plugins/workspace/public/recent_workspace_manager.ts b/src/plugins/workspace/public/recent_workspace_manager.ts new file mode 100644 index 000000000000..2bcadc72e1bd --- /dev/null +++ b/src/plugins/workspace/public/recent_workspace_manager.ts @@ -0,0 +1,51 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PersistedLog } from '../../../core/public'; +import { RECENT_WORKSPACES_KEY } from '../common/constants'; + +export interface WorkspaceEntry { + id: string; + timestamp: number; +} + +export class RecentWorkspaceManager { + private static instance: RecentWorkspaceManager; + private recentWorkspaceLog: PersistedLog; + + private constructor() { + const customIsEqual = (oldItem: WorkspaceEntry, newItem: WorkspaceEntry) => { + return oldItem.id === newItem.id; + }; + this.recentWorkspaceLog = new PersistedLog(RECENT_WORKSPACES_KEY, { + maxLength: 10, + isEqual: customIsEqual, + }); + } + + // Singleton pattern to ensure only one instance is used + public static getInstance(): RecentWorkspaceManager { + if (!RecentWorkspaceManager.instance) { + RecentWorkspaceManager.instance = new RecentWorkspaceManager(); + } + return RecentWorkspaceManager.instance; + } + + public getRecentWorkspaces(): WorkspaceEntry[] { + return this.recentWorkspaceLog.get(); + } + + public addRecentWorkspace(newWorkspace: string): WorkspaceEntry[] { + const newEntry: WorkspaceEntry = { + id: newWorkspace, + timestamp: Date.now(), + }; + this.recentWorkspaceLog.add(newEntry); + return this.getRecentWorkspaces(); + } +} + +// Export the singleton instance +export const recentWorkspaceManager = RecentWorkspaceManager.getInstance(); From 8b7e0fe3a28c0884209fde968ef05d47a251cb0e Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:30:09 +0800 Subject: [PATCH 089/276] New core plugin for dynamic content rendering (#7201) (#7330) * feat: add content management plugin * fix: add license header * add card container for rendering content as cards * rename GetStartedCard -> CardList * content management supporting embedding dashboards * rename interface VisualizationInput -> SavedObjectInput * cleanup and refactor * fix license header * add unit test for content management plugin * Add a todo to cleanup demo code * refactor: decouple content and page with content provider * fix linter * fix lint * Changeset file for PR #7201 created/updated * pr feedback updates * fix tests * fix license header * cleanup unused variable * mark registerContentProvider API as experimental --------- (cherry picked from commit cc6949b382fe1177b85906477046fa211b11cd31) Signed-off-by: Yulong Ruan Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7201.yml | 2 + .../opensearch_dashboards.json | 9 + src/plugins/content_management/public/app.tsx | 23 ++ .../card_container/card_container.test.tsx | 27 ++ .../card_container/card_container.tsx | 46 +++ .../card_container_factory.test.ts | 20 ++ .../card_container/card_container_factory.ts | 42 +++ .../card_container/card_embeddable.test.tsx | 23 ++ .../card_container/card_embeddable.tsx | 47 +++ .../card_embeddable_factory.test.ts | 17 + .../card_container/card_embeddable_factory.ts | 26 ++ .../card_container/card_list.test.tsx | 41 +++ .../components/card_container/card_list.tsx | 44 +++ .../custom_content_embeddable.test.tsx | 29 ++ .../components/custom_content_embeddable.tsx | 38 +++ .../custom_content_embeddable_factory.test.ts | 17 + .../custom_content_embeddable_factory.ts | 31 ++ .../public/components/index.ts | 6 + .../public/components/page_render.test.tsx | 36 ++ .../public/components/page_render.tsx | 36 ++ .../public/components/section_input.test.ts | 322 ++++++++++++++++++ .../public/components/section_input.ts | 196 +++++++++++ .../public/components/section_render.test.tsx | 121 +++++++ .../public/components/section_render.tsx | 97 ++++++ .../content_management/public/index.ts | 15 + .../content_management/public/mocks.ts | 24 ++ .../content_management/public/plugin.ts | 79 +++++ .../content_management_service.test.ts | 71 ++++ .../content_management_service.ts | 62 ++++ .../services/content_management/index.ts | 8 + .../services/content_management/page.test.ts | 104 ++++++ .../services/content_management/page.ts | 67 ++++ .../services/content_management/types.ts | 84 +++++ .../public/services/index.ts | 6 + .../content_management/public/types.ts | 31 ++ .../lib/embeddables/embeddable_root.tsx | 15 +- src/plugins/home/common/constants.ts | 12 + src/plugins/home/opensearch_dashboards.json | 2 +- .../public/application/components/home_app.js | 6 +- .../home/public/application/home_render.tsx | 41 +++ .../opensearch_dashboards_services.mock.ts | 2 + .../opensearch_dashboards_services.ts | 2 + src/plugins/home/public/plugin.test.ts | 6 + src/plugins/home/public/plugin.ts | 28 +- 44 files changed, 1953 insertions(+), 8 deletions(-) create mode 100644 changelogs/fragments/7201.yml create mode 100644 src/plugins/content_management/opensearch_dashboards.json create mode 100644 src/plugins/content_management/public/app.tsx create mode 100644 src/plugins/content_management/public/components/card_container/card_container.test.tsx create mode 100644 src/plugins/content_management/public/components/card_container/card_container.tsx create mode 100644 src/plugins/content_management/public/components/card_container/card_container_factory.test.ts create mode 100644 src/plugins/content_management/public/components/card_container/card_container_factory.ts create mode 100644 src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx create mode 100644 src/plugins/content_management/public/components/card_container/card_embeddable.tsx create mode 100644 src/plugins/content_management/public/components/card_container/card_embeddable_factory.test.ts create mode 100644 src/plugins/content_management/public/components/card_container/card_embeddable_factory.ts create mode 100644 src/plugins/content_management/public/components/card_container/card_list.test.tsx create mode 100644 src/plugins/content_management/public/components/card_container/card_list.tsx create mode 100644 src/plugins/content_management/public/components/custom_content_embeddable.test.tsx create mode 100644 src/plugins/content_management/public/components/custom_content_embeddable.tsx create mode 100644 src/plugins/content_management/public/components/custom_content_embeddable_factory.test.ts create mode 100644 src/plugins/content_management/public/components/custom_content_embeddable_factory.ts create mode 100644 src/plugins/content_management/public/components/index.ts create mode 100644 src/plugins/content_management/public/components/page_render.test.tsx create mode 100644 src/plugins/content_management/public/components/page_render.tsx create mode 100644 src/plugins/content_management/public/components/section_input.test.ts create mode 100644 src/plugins/content_management/public/components/section_input.ts create mode 100644 src/plugins/content_management/public/components/section_render.test.tsx create mode 100644 src/plugins/content_management/public/components/section_render.tsx create mode 100644 src/plugins/content_management/public/index.ts create mode 100644 src/plugins/content_management/public/mocks.ts create mode 100644 src/plugins/content_management/public/plugin.ts create mode 100644 src/plugins/content_management/public/services/content_management/content_management_service.test.ts create mode 100644 src/plugins/content_management/public/services/content_management/content_management_service.ts create mode 100644 src/plugins/content_management/public/services/content_management/index.ts create mode 100644 src/plugins/content_management/public/services/content_management/page.test.ts create mode 100644 src/plugins/content_management/public/services/content_management/page.ts create mode 100644 src/plugins/content_management/public/services/content_management/types.ts create mode 100644 src/plugins/content_management/public/services/index.ts create mode 100644 src/plugins/content_management/public/types.ts create mode 100644 src/plugins/home/public/application/home_render.tsx diff --git a/changelogs/fragments/7201.yml b/changelogs/fragments/7201.yml new file mode 100644 index 000000000000..d1debb8a52db --- /dev/null +++ b/changelogs/fragments/7201.yml @@ -0,0 +1,2 @@ +feat: +- Introduced an new plugin contentManagement for dynamic content rendering ([#7201](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7201)) \ No newline at end of file diff --git a/src/plugins/content_management/opensearch_dashboards.json b/src/plugins/content_management/opensearch_dashboards.json new file mode 100644 index 000000000000..fdeccc903e51 --- /dev/null +++ b/src/plugins/content_management/opensearch_dashboards.json @@ -0,0 +1,9 @@ +{ + "id": "contentManagement", + "version": "opensearchDashboards", + "server": false, + "ui": true, + "requiredPlugins": ["embeddable"], + "optionalPlugins": [], + "requiredBundles": [] +} diff --git a/src/plugins/content_management/public/app.tsx b/src/plugins/content_management/public/app.tsx new file mode 100644 index 000000000000..794d36d7e946 --- /dev/null +++ b/src/plugins/content_management/public/app.tsx @@ -0,0 +1,23 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; + +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { PageRender } from './components/page_render'; +import { Page } from './services'; +import { EmbeddableStart } from '../../embeddable/public'; + +export const renderPage = ({ + page, + embeddable, + savedObjectsClient, +}: { + page: Page; + embeddable: EmbeddableStart; + savedObjectsClient: SavedObjectsClientContract; +}) => { + return ; +}; diff --git a/src/plugins/content_management/public/components/card_container/card_container.test.tsx b/src/plugins/content_management/public/components/card_container/card_container.test.tsx new file mode 100644 index 000000000000..211b55d18423 --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_container.test.tsx @@ -0,0 +1,27 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { embeddablePluginMock } from '../../../../embeddable/public/mocks'; +import { CardContainer } from './card_container'; + +jest.mock('./card_list', () => { + return { + CardList: jest.fn().mockReturnValue(), + }; +}); + +test('CardContainer should render CardList', () => { + const container = new CardContainer( + { id: 'container-id', panels: {} }, + embeddablePluginMock.createStartContract() + ); + const node = document.createElement('div'); + container.render(node); + expect(node.querySelector('#mockCardList')).toBeTruthy(); + + container.destroy(); + expect(node.querySelector('#mockCardList')).toBeFalsy(); +}); diff --git a/src/plugins/content_management/public/components/card_container/card_container.tsx b/src/plugins/content_management/public/components/card_container/card_container.tsx new file mode 100644 index 000000000000..518734563607 --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_container.tsx @@ -0,0 +1,46 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Container, ContainerInput, EmbeddableStart } from '../../../../embeddable/public'; +import { CardList } from './card_list'; + +export const CARD_CONTAINER = 'CARD_CONTAINER'; + +export type CardContainerInput = ContainerInput<{ description: string; onClick?: () => void }>; + +export class CardContainer extends Container<{}, CardContainerInput> { + public readonly type = CARD_CONTAINER; + private node?: HTMLElement; + + constructor(input: CardContainerInput, private embeddableServices: EmbeddableStart) { + super(input, { embeddableLoaded: {} }, embeddableServices.getEmbeddableFactory); + } + + getInheritedInput() { + return { + viewMode: this.input.viewMode, + }; + } + + public render(node: HTMLElement) { + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + this.node = node; + ReactDOM.render( + , + node + ); + } + + public destroy() { + super.destroy(); + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + } +} diff --git a/src/plugins/content_management/public/components/card_container/card_container_factory.test.ts b/src/plugins/content_management/public/components/card_container/card_container_factory.test.ts new file mode 100644 index 000000000000..85da97a3294f --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_container_factory.test.ts @@ -0,0 +1,20 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { embeddablePluginMock } from '../../../../embeddable/public/mocks'; +import { CARD_CONTAINER, CardContainer } from './card_container'; +import { CardContainerFactoryDefinition } from './card_container_factory'; + +test('CardContainerFactoryDefinition', async () => { + const getStartServices = jest + .fn() + .mockResolvedValue({ embeddableServices: embeddablePluginMock.createStartContract() }); + const factory = new CardContainerFactoryDefinition(getStartServices); + expect(factory.type).toBe(CARD_CONTAINER); + expect(factory.isContainerType).toBe(true); + expect(await factory.isEditable()).toBe(false); + expect(factory.getDisplayName()).toBe('Card container'); + expect(await factory.create({ id: 'card-id', panels: {} })).toBeInstanceOf(CardContainer); +}); diff --git a/src/plugins/content_management/public/components/card_container/card_container_factory.ts b/src/plugins/content_management/public/components/card_container/card_container_factory.ts new file mode 100644 index 000000000000..ba7f8fc1d07c --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_container_factory.ts @@ -0,0 +1,42 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; + +import { + EmbeddableFactoryDefinition, + EmbeddableStart, + EmbeddableFactory, + ContainerOutput, +} from '../../../../embeddable/public'; +import { CARD_CONTAINER, CardContainer, CardContainerInput } from './card_container'; + +interface StartServices { + embeddableServices: EmbeddableStart; +} + +export type CardContainerFactory = EmbeddableFactory; +export class CardContainerFactoryDefinition + implements EmbeddableFactoryDefinition { + public readonly type = CARD_CONTAINER; + public readonly isContainerType = true; + + constructor(private getStartServices: () => Promise) {} + + public async isEditable() { + return false; + } + + public create = async (initialInput: CardContainerInput) => { + const { embeddableServices } = await this.getStartServices(); + return new CardContainer(initialInput, embeddableServices); + }; + + public getDisplayName() { + return i18n.translate('contentManagement.cardContainer.displayName', { + defaultMessage: 'Card container', + }); + } +} diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx new file mode 100644 index 000000000000..b335bac6d996 --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx @@ -0,0 +1,23 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CardEmbeddable } from './card_embeddable'; + +test('CardEmbeddable should render a card with the title', () => { + const embeddable = new CardEmbeddable({ id: 'card-id', title: 'card title', description: '' }); + + const node = document.createElement('div'); + embeddable.render(node); + + // it should render the card with title specified + expect( + Array.from(node.querySelectorAll('*')).find((ele) => ele.textContent?.trim() === 'card title') + ).toBeTruthy(); + + embeddable.destroy(); + expect( + Array.from(node.querySelectorAll('*')).find((ele) => ele.textContent?.trim() === 'card title') + ).toBeFalsy(); +}); diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx new file mode 100644 index 000000000000..844cf13a777c --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { EuiCard } from '@elastic/eui'; + +import { Embeddable, EmbeddableInput, IContainer } from '../../../../embeddable/public'; + +export const CARD_EMBEDDABLE = 'card_embeddable'; +export type CardEmbeddableInput = EmbeddableInput & { description: string; onClick?: () => void }; + +export class CardEmbeddable extends Embeddable { + public readonly type = CARD_EMBEDDABLE; + private node: HTMLElement | null = null; + + constructor(initialInput: CardEmbeddableInput, parent?: IContainer) { + super(initialInput, {}, parent); + } + + public render(node: HTMLElement) { + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + this.node = node; + ReactDOM.render( + , + node + ); + } + + public destroy() { + super.destroy(); + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + } + + public reload() {} +} diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable_factory.test.ts b/src/plugins/content_management/public/components/card_container/card_embeddable_factory.test.ts new file mode 100644 index 000000000000..2455c0b76155 --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_embeddable_factory.test.ts @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CARD_EMBEDDABLE, CardEmbeddable } from './card_embeddable'; +import { CardEmbeddableFactoryDefinition } from './card_embeddable_factory'; + +test('create CardEmbeddableFactoryDefinition', async () => { + const factory = new CardEmbeddableFactoryDefinition(); + expect(factory.type).toBe(CARD_EMBEDDABLE); + expect(factory.getDisplayName()).toBe('Card'); + expect(await factory.isEditable()).toBe(false); + expect(await factory.create({ id: 'card-id', title: 'title', description: '' })).toBeInstanceOf( + CardEmbeddable + ); +}); diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable_factory.ts b/src/plugins/content_management/public/components/card_container/card_embeddable_factory.ts new file mode 100644 index 000000000000..01ab709bfd79 --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_embeddable_factory.ts @@ -0,0 +1,26 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import { EmbeddableFactoryDefinition, IContainer } from '../../../../embeddable/public'; +import { CARD_EMBEDDABLE, CardEmbeddable, CardEmbeddableInput } from './card_embeddable'; + +export class CardEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { + public readonly type = CARD_EMBEDDABLE; + + public async isEditable() { + return false; + } + + public async create(initialInput: CardEmbeddableInput, parent?: IContainer) { + return new CardEmbeddable(initialInput, parent); + } + + public getDisplayName() { + return i18n.translate('contentManagement.embeddable.card', { + defaultMessage: 'Card', + }); + } +} diff --git a/src/plugins/content_management/public/components/card_container/card_list.test.tsx b/src/plugins/content_management/public/components/card_container/card_list.test.tsx new file mode 100644 index 000000000000..fce99b3e6174 --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_list.test.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; + +import { CardList } from './card_list'; +import { CardContainer } from './card_container'; +import { embeddablePluginMock } from '../../../../embeddable/public/mocks'; +import { CARD_EMBEDDABLE } from './card_embeddable'; + +beforeEach(() => { + jest.restoreAllMocks(); +}); + +test('render list of cards', () => { + const embeddableStart = embeddablePluginMock.createStartContract(); + jest + .spyOn(embeddableStart, 'EmbeddablePanel') + .mockImplementation(() => CardEmbeddablePanel); + render( + + ); + expect(screen.queryAllByText('CardEmbeddablePanel')).toHaveLength(2); +}); diff --git a/src/plugins/content_management/public/components/card_container/card_list.tsx b/src/plugins/content_management/public/components/card_container/card_list.tsx new file mode 100644 index 000000000000..b9619d39e0d1 --- /dev/null +++ b/src/plugins/content_management/public/components/card_container/card_list.tsx @@ -0,0 +1,44 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; + +import { + IContainer, + withEmbeddableSubscription, + ContainerInput, + ContainerOutput, + EmbeddableStart, +} from '../../../../embeddable/public'; + +interface Props { + embeddable: IContainer; + input: ContainerInput; + embeddableServices: EmbeddableStart; +} + +const CardListInner = ({ embeddable, input, embeddableServices }: Props) => { + const cards = Object.values(input.panels).map((panel) => { + const child = embeddable.getChild(panel.explicitInput.id); + return ( + + + + ); + }); + return ( + + {cards} + + ); +}; + +export const CardList = withEmbeddableSubscription< + ContainerInput, + ContainerOutput, + IContainer, + { embeddableServices: EmbeddableStart } +>(CardListInner); diff --git a/src/plugins/content_management/public/components/custom_content_embeddable.test.tsx b/src/plugins/content_management/public/components/custom_content_embeddable.test.tsx new file mode 100644 index 000000000000..979a82626191 --- /dev/null +++ b/src/plugins/content_management/public/components/custom_content_embeddable.test.tsx @@ -0,0 +1,29 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; + +import { CustomContentEmbeddable } from './custom_content_embeddable'; + +test('CustomContentEmbeddable', () => { + const mockRender = jest.fn().mockReturnValue(custom content); + const embeddable = new CustomContentEmbeddable({ id: 'id', render: mockRender }); + const node = document.createElement('div'); + + // it render the custom content which content defined by a `render` function + embeddable.render(node); + expect( + Array.from(node.querySelectorAll('*')).find( + (ele) => ele.textContent?.trim() === 'custom content' + ) + ).toBeTruthy(); + + embeddable.destroy(); + expect( + Array.from(node.querySelectorAll('*')).find( + (ele) => ele.textContent?.trim() === 'custom content' + ) + ).toBeFalsy(); +}); diff --git a/src/plugins/content_management/public/components/custom_content_embeddable.tsx b/src/plugins/content_management/public/components/custom_content_embeddable.tsx new file mode 100644 index 000000000000..df67b340a4ba --- /dev/null +++ b/src/plugins/content_management/public/components/custom_content_embeddable.tsx @@ -0,0 +1,38 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; + +import { Embeddable, EmbeddableInput, IContainer } from '../../../embeddable/public'; + +export const CUSTOM_CONTENT_EMBEDDABLE = 'custom_content_embeddable'; +export type CustomContentEmbeddableInput = EmbeddableInput & { render: () => React.ReactElement }; + +export class CustomContentEmbeddable extends Embeddable { + public readonly type = CUSTOM_CONTENT_EMBEDDABLE; + private node: HTMLElement | null = null; + + constructor(initialInput: CustomContentEmbeddableInput, parent?: IContainer) { + super(initialInput, {}, parent); + } + + public render(node: HTMLElement) { + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + this.node = node; + ReactDOM.render(this.input.render(), node); + } + + public destroy() { + super.destroy(); + if (this.node) { + ReactDOM.unmountComponentAtNode(this.node); + } + } + + public reload() {} +} diff --git a/src/plugins/content_management/public/components/custom_content_embeddable_factory.test.ts b/src/plugins/content_management/public/components/custom_content_embeddable_factory.test.ts new file mode 100644 index 000000000000..c5bc306c791f --- /dev/null +++ b/src/plugins/content_management/public/components/custom_content_embeddable_factory.test.ts @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CUSTOM_CONTENT_EMBEDDABLE, CustomContentEmbeddable } from './custom_content_embeddable'; +import { CustomContentEmbeddableFactoryDefinition } from './custom_content_embeddable_factory'; + +test('create CustomContentEmbeddableFactory', async () => { + const factory = new CustomContentEmbeddableFactoryDefinition(); + expect(factory.type).toBe(CUSTOM_CONTENT_EMBEDDABLE); + expect(await factory.isEditable()).toBe(false); + expect(factory.getDisplayName()).toBe('Content'); + expect(await factory.create({ id: 'id', render: jest.fn() })).toBeInstanceOf( + CustomContentEmbeddable + ); +}); diff --git a/src/plugins/content_management/public/components/custom_content_embeddable_factory.ts b/src/plugins/content_management/public/components/custom_content_embeddable_factory.ts new file mode 100644 index 000000000000..fb543f071c5e --- /dev/null +++ b/src/plugins/content_management/public/components/custom_content_embeddable_factory.ts @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; + +import { EmbeddableFactoryDefinition, IContainer } from '../../../embeddable/public'; +import { + CUSTOM_CONTENT_EMBEDDABLE, + CustomContentEmbeddable, + CustomContentEmbeddableInput, +} from './custom_content_embeddable'; + +export class CustomContentEmbeddableFactoryDefinition implements EmbeddableFactoryDefinition { + public readonly type = CUSTOM_CONTENT_EMBEDDABLE; + + public async isEditable() { + return false; + } + + public async create(initialInput: CustomContentEmbeddableInput, parent?: IContainer) { + return new CustomContentEmbeddable(initialInput, parent); + } + + public getDisplayName() { + return i18n.translate('contentManagement.embeddable.customContent', { + defaultMessage: 'Content', + }); + } +} diff --git a/src/plugins/content_management/public/components/index.ts b/src/plugins/content_management/public/components/index.ts new file mode 100644 index 000000000000..b83d733fc0f8 --- /dev/null +++ b/src/plugins/content_management/public/components/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './page_render'; diff --git a/src/plugins/content_management/public/components/page_render.test.tsx b/src/plugins/content_management/public/components/page_render.test.tsx new file mode 100644 index 000000000000..88a61fda0018 --- /dev/null +++ b/src/plugins/content_management/public/components/page_render.test.tsx @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, screen } from '@testing-library/react'; + +import { coreMock } from '../../../../core/public/mocks'; +import { PageRender } from './page_render'; +import { Page } from '../services'; +import { embeddablePluginMock } from '../../../embeddable/public/mocks'; + +jest.mock('./section_render', () => { + return { + ...jest.requireActual('./section_render'), + SectionRender: jest.fn().mockReturnValue(MockSectionRender), + }; +}); + +test('it should render the sections', () => { + const page = new Page({ id: 'page1' }); + page.createSection({ id: 's1', kind: 'card', order: 10 }); + page.createSection({ id: 's2', kind: 'custom', order: 10, render: jest.fn() }); + page.createSection({ id: 's3', kind: 'dashboard', order: 10 }); + + render( + + ); + + expect(screen.queryAllByText('MockSectionRender')).toHaveLength(3); +}); diff --git a/src/plugins/content_management/public/components/page_render.tsx b/src/plugins/content_management/public/components/page_render.tsx new file mode 100644 index 000000000000..9a5211ca3a46 --- /dev/null +++ b/src/plugins/content_management/public/components/page_render.tsx @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { useObservable } from 'react-use'; +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; + +import { Page } from '../services'; +import { SectionRender } from './section_render'; +import { EmbeddableStart } from '../../../embeddable/public'; + +export interface Props { + page: Page; + embeddable: EmbeddableStart; + savedObjectsClient: SavedObjectsClientContract; +} + +export const PageRender = ({ page, embeddable, savedObjectsClient }: Props) => { + const sections = useObservable(page.getSections$()) || []; + + return ( +
+ {sections.map((section) => ( + + ))} +
+ ); +}; diff --git a/src/plugins/content_management/public/components/section_input.test.ts b/src/plugins/content_management/public/components/section_input.test.ts new file mode 100644 index 000000000000..22420e071438 --- /dev/null +++ b/src/plugins/content_management/public/components/section_input.test.ts @@ -0,0 +1,322 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { coreMock } from '../../../../core/public/mocks'; +import { Content, Section } from '../services'; +import { createCardInput, createDashboardInput } from './section_input'; + +test('it should create input for card section', () => { + const section: Section = { id: 'section1', kind: 'card', order: 10 }; + const content: Content = { + id: 'content1', + kind: 'card', + order: 0, + title: 'content title', + description: 'content description', + }; + const input = createCardInput(section, [content]); + expect(input).toEqual({ + id: 'section1', + title: '', + hidePanelTitles: true, + viewMode: 'view', + panels: { + content1: { + type: 'card_embeddable', + explicitInput: { + description: 'content description', + id: 'content1', + onClick: undefined, + title: 'content title', + }, + }, + }, + }); +}); + +test('it should not allow to create card input with non-card section', () => { + const section: Section = { id: 'section1', kind: 'dashboard', order: 10 }; + const content: Content = { + id: 'content1', + kind: 'card', + order: 0, + title: 'content title', + description: 'content description', + }; + expect(() => createCardInput(section, [content])).toThrowError(); +}); + +test('card section should not include non-card content', () => { + const section: Section = { id: 'section1', kind: 'card', order: 10 }; + const content: Content = { + id: 'content1', + kind: 'visualization', + order: 0, + input: { + kind: 'static', + id: 'viz-id', + }, + }; + const input = createCardInput(section, [content]); + expect(input).toBe(null); +}); + +test('it should throw error if creating dashboard input with non-dashboard section', async () => { + const section: Section = { id: 'section1', kind: 'card', order: 10 }; + const content: Content = { + id: 'content1', + kind: 'card', + order: 0, + title: 'content title', + description: 'content description', + }; + const clientMock = coreMock.createStart().savedObjects.client; + await expect( + async () => await createDashboardInput(section, [content], { savedObjectsClient: clientMock }) + ).rejects.toThrowError(); +}); + +test('it should create dashboard input', async () => { + const section: Section = { id: 'section1', kind: 'dashboard', order: 10 }; + const staticViz: Content = { + id: 'content1', + kind: 'visualization', + order: 0, + input: { + kind: 'static', + id: 'viz-id-static', + }, + }; + + const dynamicViz: Content = { + id: 'content2', + kind: 'visualization', + order: 10, + input: { + kind: 'dynamic', + get: () => Promise.resolve('viz-id-dynamic'), + }, + }; + + const renderFn = jest.fn(); + const customRender: Content = { + id: 'content3', + kind: 'custom', + order: 20, + render: renderFn, + }; + const clientMock = coreMock.createStart().savedObjects.client; + const input = await createDashboardInput(section, [staticViz, dynamicViz, customRender], { + savedObjectsClient: clientMock, + }); + + expect(input.panels).toEqual({ + content1: { + explicitInput: { + disabledActions: ['togglePanel'], + id: 'content1', + savedObjectId: 'viz-id-static', + }, + gridData: { + h: 15, + i: 'content1', + w: 12, + x: 0, + y: 0, + }, + type: 'visualization', + }, + content2: { + explicitInput: { + disabledActions: ['togglePanel'], + id: 'content2', + savedObjectId: 'viz-id-dynamic', + }, + gridData: { + h: 15, + i: 'content2', + w: 12, + x: 12, + y: 0, + }, + type: 'visualization', + }, + content3: { + explicitInput: { + disabledActions: ['togglePanel'], + id: 'content3', + render: renderFn, + }, + gridData: { + h: 15, + i: 'content3', + w: 12, + x: 24, + y: 0, + }, + type: 'custom_content_embeddable', + }, + }); +}); + +test('it should create dashboard input without the content which throws error', async () => { + const section: Section = { id: 'section1', kind: 'dashboard', order: 10 }; + const staticViz: Content = { + id: 'content1', + kind: 'visualization', + order: 0, + input: { + kind: 'static', + id: 'viz-id-static', + }, + }; + + const dynamicViz: Content = { + id: 'content2', + kind: 'visualization', + order: 10, + input: { + kind: 'dynamic', + get: () => Promise.reject('error'), + }, + }; + + const renderFn = jest.fn(); + const customRender: Content = { + id: 'content3', + kind: 'custom', + order: 20, + render: renderFn, + }; + const clientMock = coreMock.createStart().savedObjects.client; + const input = await createDashboardInput(section, [staticViz, dynamicViz, customRender], { + savedObjectsClient: clientMock, + }); + + expect(input.panels).toEqual({ + content1: { + explicitInput: { + disabledActions: ['togglePanel'], + id: 'content1', + savedObjectId: 'viz-id-static', + }, + gridData: { + h: 15, + i: 'content1', + w: 12, + x: 0, + y: 0, + }, + type: 'visualization', + }, + content3: { + explicitInput: { + disabledActions: ['togglePanel'], + id: 'content3', + render: renderFn, + }, + gridData: { + h: 15, + i: 'content3', + w: 12, + x: 24, + y: 0, + }, + type: 'custom_content_embeddable', + }, + }); +}); + +test('it should create section with a dashboard as content', async () => { + const section: Section = { id: 'section1', kind: 'dashboard', order: 10 }; + const staticDashboard: Content = { + id: 'content1', + kind: 'dashboard', + order: 0, + input: { + kind: 'static', + id: 'dashboard-id-static', + }, + }; + const clientMock = { + ...coreMock.createStart().savedObjects.client, + get: jest.fn().mockResolvedValue({ + id: 'dashboard-id-static', + attributes: { + panelsJSON: + '[{"version":"3.0.0","gridData":{"x":0,"y":0,"w":48,"h":5,"i":"debc95ec-7d43-49ee-84c8-95ad7b0b03ea"},"panelIndex":"debc95ec-7d43-49ee-84c8-95ad7b0b03ea","embeddableConfig":{"hidePanelTitles":true},"panelRefName":"panel_0"}]', + }, + references: [ + { id: 'ce24dd10-eb8a-11ed-8e00-17d7d50cd7b2', name: 'panel_0', type: 'visualization' }, + ], + }), + }; + + const input = await createDashboardInput(section, [staticDashboard], { + savedObjectsClient: clientMock, + }); + expect(input.panels).toEqual({ + 'debc95ec-7d43-49ee-84c8-95ad7b0b03ea': { + explicitInput: { + id: 'debc95ec-7d43-49ee-84c8-95ad7b0b03ea', + savedObjectId: 'ce24dd10-eb8a-11ed-8e00-17d7d50cd7b2', + }, + gridData: { + h: 5, + i: 'debc95ec-7d43-49ee-84c8-95ad7b0b03ea', + w: 48, + x: 0, + y: 0, + }, + type: 'visualization', + }, + }); +}); + +test('it should create section with a dynamic dashboard as content', async () => { + const section: Section = { id: 'section1', kind: 'dashboard', order: 10 }; + const staticDashboard: Content = { + id: 'content1', + kind: 'dashboard', + order: 0, + input: { + kind: 'dynamic', + get: () => Promise.resolve('dashboard-id-static'), + }, + }; + const clientMock = { + ...coreMock.createStart().savedObjects.client, + get: jest.fn().mockResolvedValue({ + id: 'dashboard-id-static', + attributes: { + panelsJSON: + '[{"version":"3.0.0","gridData":{"x":0,"y":0,"w":48,"h":5,"i":"debc95ec-7d43-49ee-84c8-95ad7b0b03ea"},"panelIndex":"debc95ec-7d43-49ee-84c8-95ad7b0b03ea","embeddableConfig":{"hidePanelTitles":true},"panelRefName":"panel_0"}]', + }, + references: [ + { id: 'ce24dd10-eb8a-11ed-8e00-17d7d50cd7b2', name: 'panel_0', type: 'visualization' }, + ], + }), + }; + + const input = await createDashboardInput(section, [staticDashboard], { + savedObjectsClient: clientMock, + }); + expect(input.panels).toEqual({ + 'debc95ec-7d43-49ee-84c8-95ad7b0b03ea': { + explicitInput: { + id: 'debc95ec-7d43-49ee-84c8-95ad7b0b03ea', + savedObjectId: 'ce24dd10-eb8a-11ed-8e00-17d7d50cd7b2', + }, + gridData: { + h: 5, + i: 'debc95ec-7d43-49ee-84c8-95ad7b0b03ea', + w: 48, + x: 0, + y: 0, + }, + type: 'visualization', + }, + }); +}); diff --git a/src/plugins/content_management/public/components/section_input.ts b/src/plugins/content_management/public/components/section_input.ts new file mode 100644 index 000000000000..1d37feef8ecc --- /dev/null +++ b/src/plugins/content_management/public/components/section_input.ts @@ -0,0 +1,196 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { BehaviorSubject } from 'rxjs'; +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; + +import { Content, Section } from '../services'; +import { ViewMode } from '../../../embeddable/public'; +import { DashboardContainerInput, SavedObjectDashboard } from '../../../dashboard/public'; +import { CUSTOM_CONTENT_EMBEDDABLE } from './custom_content_embeddable'; +import { CardContainerInput } from './card_container/card_container'; +import { CARD_EMBEDDABLE } from './card_container/card_embeddable'; + +const DASHBOARD_GRID_COLUMN_COUNT = 48; + +export const createCardInput = ( + section: Section, + contents: Content[] +): CardContainerInput | null => { + if (section.kind !== 'card') { + throw new Error(`function does not support section.type: ${section.kind}`); + } + + const panels: CardContainerInput['panels'] = {}; + + const input: CardContainerInput = { + id: section.id, + title: section.title ?? '', + hidePanelTitles: true, + viewMode: ViewMode.VIEW, + panels, + }; + + contents.forEach((content) => { + if (content.kind === 'card') { + panels[content.id] = { + type: CARD_EMBEDDABLE, + explicitInput: { + id: content.id, + title: content.title, + description: content.description, + onClick: content.onClick, + }, + }; + } + }); + + if (Object.keys(panels).length === 0) { + return null; + } + + return input; +}; + +export const createDashboardInput = async ( + section: Section, + contents: Content[], + services: { savedObjectsClient: SavedObjectsClientContract } +) => { + if (section.kind !== 'dashboard') { + throw new Error(`function does not support section.type: ${section.kind}`); + } + + // TODO: support different panel size + const panels: DashboardContainerInput['panels'] = {}; + let x = 0; + let y = 0; + const w = 12; + const h = 15; + const counter = new BehaviorSubject(0); + + contents.forEach(async (content, i) => { + counter.next(counter.value + 1); + try { + if (content.kind === 'dashboard') { + let dashboardId = ''; + if (content.input.kind === 'dynamic') { + dashboardId = await content.input.get(); + } + + if (content.input.kind === 'static') { + dashboardId = content.input.id; + } + + if (dashboardId) { + const dashboardObject = await services.savedObjectsClient.get( + 'dashboard', + dashboardId + ); + const references = dashboardObject.references; + const savedObject = dashboardObject.attributes; + if (savedObject.panelsJSON && typeof savedObject.panelsJSON === 'string') { + const dashboardPanels = JSON.parse(savedObject.panelsJSON); + if (Array.isArray(dashboardPanels)) { + dashboardPanels.forEach((panel) => { + if (!panel.panelRefName) { + return; + } + const reference = references.find((ref) => ref.name === panel.panelRefName); + if (reference) { + panels[panel.panelIndex] = { + gridData: panel.gridData, + type: reference.type, + explicitInput: { + id: panel.panelIndex, + savedObjectId: reference.id, + }, + }; + } + }); + } + } + } + return; + } + + const config: DashboardContainerInput['panels'][string] = { + gridData: { + w, + h, + x, + y, + i: content.id, + }, + type: '', + explicitInput: { + id: content.id, + disabledActions: ['togglePanel'], + }, + }; + + x = x + w; + if (x >= DASHBOARD_GRID_COLUMN_COUNT) { + x = 0; + y = y + h; + } + + if (content.kind === 'visualization') { + config.type = 'visualization'; + if (content.input.kind === 'dynamic') { + config.explicitInput.savedObjectId = await content.input.get(); + } + if (content.input.kind === 'static') { + config.explicitInput.savedObjectId = content.input.id; + } + } + + if (content.kind === 'custom') { + config.type = CUSTOM_CONTENT_EMBEDDABLE; + config.explicitInput.render = content.render; + } + + panels[content.id] = config; + } catch (e) { + // eslint-disable-next-line + console.log(e); + } finally { + counter.next(counter.value - 1); + } + }); + + /** + * TODO: the input should be hooked with query input + */ + const input: DashboardContainerInput = { + viewMode: ViewMode.VIEW, + panels, + isFullScreenMode: false, + filters: [], + useMargins: true, + id: section.id, + timeRange: { + to: 'now', + from: 'now-7d', + }, + title: section.title ?? 'test', + query: { + query: '', + language: 'lucene', + }, + refreshConfig: { + pause: true, + value: 15, + }, + }; + + return new Promise((resolve) => { + counter.subscribe((n) => { + if (n === 0) { + resolve(input); + } + }); + }); +}; diff --git a/src/plugins/content_management/public/components/section_render.test.tsx b/src/plugins/content_management/public/components/section_render.test.tsx new file mode 100644 index 000000000000..848523e8af33 --- /dev/null +++ b/src/plugins/content_management/public/components/section_render.test.tsx @@ -0,0 +1,121 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import { SectionRender } from './section_render'; +import { Content, Section } from '../services'; +import { embeddablePluginMock } from '../../../embeddable/public/mocks'; +import { coreMock } from '../../../../core/public/mocks'; +import { BehaviorSubject } from 'rxjs'; +import * as SectionInputExports from './section_input'; +import { DashboardContainerInput } from '../../../dashboard/public'; +import { ContainerInput } from '../../../embeddable/public'; + +jest.mock('../../../embeddable/public', () => { + return { + ...jest.requireActual('../../../embeddable/public'), + EmbeddableRenderer: jest.fn().mockImplementation(() => MockEmbeddableRenderer), + }; +}); + +beforeEach(() => { + jest.restoreAllMocks(); +}); + +test('it should render custom section', () => { + const section: Section = { + id: 'section1', + kind: 'custom', + order: 10, + render: (contents) => ( + + {contents.map((c) => c.kind === 'custom' && {c.render()})} + + ), + }; + render( + ([ + { id: 'content1', kind: 'custom', order: 10, render: () => custom content }, + ]) + } + /> + ); + expect(screen.getByText('custom content')).toBeInTheDocument(); +}); + +test('it should render dashboard section', async () => { + jest + .spyOn(SectionInputExports, 'createDashboardInput') + .mockResolvedValue({} as DashboardContainerInput); + + const section: Section = { + id: 'section1', + kind: 'dashboard', + order: 10, + }; + const embeddableMock = embeddablePluginMock.createStartContract(); + + const factoryMock = jest.fn(); + embeddableMock.getEmbeddableFactory.mockReturnValue(factoryMock as any); + + render( + ([ + { + id: 'content1', + kind: 'visualization', + order: 10, + input: { kind: 'static', id: 'viz-id' }, + }, + ]) + } + /> + ); + await waitFor(() => expect(screen.getByText('MockEmbeddableRenderer')).toBeInTheDocument()); +}); + +test('it should render card section', async () => { + jest.spyOn(SectionInputExports, 'createCardInput').mockReturnValue({} as ContainerInput); + + const section: Section = { + id: 'section1', + kind: 'card', + order: 10, + }; + const embeddableMock = embeddablePluginMock.createStartContract(); + + const factoryMock = jest.fn(); + embeddableMock.getEmbeddableFactory.mockReturnValue(factoryMock as any); + + render( + ([ + { + id: 'content1', + kind: 'card', + order: 10, + title: 'title', + description: 'description', + }, + ]) + } + /> + ); + await waitFor(() => expect(screen.getByText('MockEmbeddableRenderer')).toBeInTheDocument()); +}); diff --git a/src/plugins/content_management/public/components/section_render.tsx b/src/plugins/content_management/public/components/section_render.tsx new file mode 100644 index 000000000000..19f14bdb1d67 --- /dev/null +++ b/src/plugins/content_management/public/components/section_render.tsx @@ -0,0 +1,97 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState, useEffect, useMemo } from 'react'; +import { useObservable } from 'react-use'; +import { BehaviorSubject } from 'rxjs'; +import { EuiTitle } from '@elastic/eui'; +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; + +import { Content, Section } from '../services'; +import { EmbeddableInput, EmbeddableRenderer, EmbeddableStart } from '../../../embeddable/public'; +import { DashboardContainerInput } from '../../../dashboard/public'; +import { createCardInput, createDashboardInput } from './section_input'; +import { CARD_CONTAINER } from './card_container/card_container'; + +interface Props { + section: Section; + contents$: BehaviorSubject; + embeddable: EmbeddableStart; + savedObjectsClient: SavedObjectsClientContract; +} + +export interface CardInput extends EmbeddableInput { + description: string; +} + +const DashboardSection = ({ section, embeddable, contents$, savedObjectsClient }: Props) => { + const contents = useObservable(contents$); + const [input, setInput] = useState(); + + useEffect(() => { + if (section.kind === 'dashboard') { + createDashboardInput(section, contents ?? [], { savedObjectsClient }).then((ds) => + setInput(ds) + ); + } + }, [section, contents, savedObjectsClient]); + + const factory = embeddable.getEmbeddableFactory('dashboard'); + + if (section.kind === 'dashboard' && factory && input) { + // const input = createDashboardSection(section, contents ?? []); + return ; + } + + return null; +}; + +const CardSection = ({ section, embeddable, contents$ }: Props) => { + const contents = useObservable(contents$); + const input = useMemo(() => { + return createCardInput(section, contents ?? []); + }, [section, contents]); + + const factory = embeddable.getEmbeddableFactory(CARD_CONTAINER); + + if (section.kind === 'card' && factory && input) { + return ( +
+ +

{section.title}

+
+ +
+ ); + } + + return null; +}; + +const CustomSection = ({ section, contents$ }: Props) => { + const contents = useObservable(contents$); + + if (section.kind === 'custom' && contents) { + return section.render(contents); + } + + return null; +}; + +export const SectionRender = (props: Props) => { + if (props.section.kind === 'dashboard') { + return ; + } + + if (props.section.kind === 'card') { + return ; + } + + if (props.section.kind === 'custom') { + return ; + } + + return null; +}; diff --git a/src/plugins/content_management/public/index.ts b/src/plugins/content_management/public/index.ts new file mode 100644 index 000000000000..c453782a7a9b --- /dev/null +++ b/src/plugins/content_management/public/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PluginInitializerContext } from 'opensearch-dashboards/public'; + +export { ContentManagementPluginSetup, ContentManagementPluginStart } from './types'; +import { ContentManagementPublicPlugin } from './plugin'; + +export const plugin = (initializerContext: PluginInitializerContext) => + new ContentManagementPublicPlugin(initializerContext); + +export * from './components'; +export * from './mocks'; diff --git a/src/plugins/content_management/public/mocks.ts b/src/plugins/content_management/public/mocks.ts new file mode 100644 index 000000000000..8f99be090231 --- /dev/null +++ b/src/plugins/content_management/public/mocks.ts @@ -0,0 +1,24 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ContentManagementPluginSetup, ContentManagementPluginStart } from './types'; + +const createStartContract = (): ContentManagementPluginStart => { + return { + registerContentProvider: jest.fn(), + renderPage: jest.fn(), + }; +}; + +const createSetupContract = (): ContentManagementPluginSetup => { + return { + registerPage: jest.fn(), + }; +}; + +export const contentManagementPluginMocks = { + createStartContract, + createSetupContract, +}; diff --git a/src/plugins/content_management/public/plugin.ts b/src/plugins/content_management/public/plugin.ts new file mode 100644 index 000000000000..065a85dd1262 --- /dev/null +++ b/src/plugins/content_management/public/plugin.ts @@ -0,0 +1,79 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '../../../core/public'; + +import { ContentManagementService } from './services'; +import { + ContentManagementPluginSetup, + ContentManagementPluginSetupDependencies, + ContentManagementPluginStart, + ContentManagementPluginStartDependencies, +} from './types'; +import { CUSTOM_CONTENT_EMBEDDABLE } from './components/custom_content_embeddable'; +import { CustomContentEmbeddableFactoryDefinition } from './components/custom_content_embeddable_factory'; +import { CARD_CONTAINER } from './components/card_container/card_container'; +import { CardContainerFactoryDefinition } from './components/card_container/card_container_factory'; +import { CARD_EMBEDDABLE } from './components/card_container/card_embeddable'; +import { CardEmbeddableFactoryDefinition } from './components/card_container/card_embeddable_factory'; +import { renderPage } from './app'; + +export class ContentManagementPublicPlugin + implements + Plugin< + ContentManagementPluginSetup, + ContentManagementPluginStart, + {}, + ContentManagementPluginStartDependencies + > { + private readonly contentManagementService = new ContentManagementService(); + + constructor(private readonly initializerContext: PluginInitializerContext) {} + + public setup( + core: CoreSetup, + deps: ContentManagementPluginSetupDependencies + ) { + this.contentManagementService.setup(); + + deps.embeddable.registerEmbeddableFactory( + CUSTOM_CONTENT_EMBEDDABLE, + new CustomContentEmbeddableFactoryDefinition() + ); + + deps.embeddable.registerEmbeddableFactory( + CARD_EMBEDDABLE, + new CardEmbeddableFactoryDefinition() + ); + + deps.embeddable.registerEmbeddableFactory( + CARD_CONTAINER, + new CardContainerFactoryDefinition(async () => ({ + embeddableServices: (await core.getStartServices())[1].embeddable, + })) + ); + + return { + registerPage: this.contentManagementService.registerPage, + }; + } + + public start(core: CoreStart, depsStart: ContentManagementPluginStartDependencies) { + this.contentManagementService.start(); + return { + registerContentProvider: this.contentManagementService.registerContentProvider, + renderPage: (id: string) => { + const page = this.contentManagementService.getPage(id); + if (page) { + return renderPage({ + page, + embeddable: depsStart.embeddable, + savedObjectsClient: core.savedObjects.client, + }); + } + }, + }; + } +} diff --git a/src/plugins/content_management/public/services/content_management/content_management_service.test.ts b/src/plugins/content_management/public/services/content_management/content_management_service.test.ts new file mode 100644 index 000000000000..a73d666387aa --- /dev/null +++ b/src/plugins/content_management/public/services/content_management/content_management_service.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ContentManagementService } from './content_management_service'; + +test('it should register pages', () => { + const cms = new ContentManagementService(); + cms.registerPage({ id: 'page1' }); + cms.registerPage({ id: 'page2' }); + + expect(cms.getPage('page1')).not.toBeUndefined(); + expect(cms.getPage('page2')).not.toBeUndefined(); +}); + +test('it register page with sections', () => { + const cms = new ContentManagementService(); + cms.registerPage({ id: 'page1', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); + expect(cms.getPage('page1')?.getSections()).toHaveLength(1); +}); + +test('it should throw error when register page with the same id', () => { + const cms = new ContentManagementService(); + cms.registerPage({ id: 'page1' }); + expect(() => cms.registerPage({ id: 'page1' })).toThrowError(); +}); + +test('it register content provider', () => { + const cms = new ContentManagementService(); + cms.registerPage({ id: 'page1', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); + cms.registerContentProvider({ + id: 'content_provider1', + getTargetArea() { + return 'page1/section1'; + }, + getContent() { + return { + kind: 'card', + id: 'content1', + title: 'card', + description: 'descriptions', + order: 0, + }; + }, + }); + expect(cms.getPage('page1')?.getContents('section1')).toHaveLength(1); +}); + +test('it should throw error when register content provider with invalid target area', () => { + const cms = new ContentManagementService(); + cms.registerPage({ id: 'page1', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); + expect(() => + cms.registerContentProvider({ + id: 'content_provider1', + getTargetArea() { + // valid area should be in format `${pageId}/${sectionId}` + return 'invalid_target_area'; + }, + getContent() { + return { + kind: 'card', + id: 'content1', + title: 'card', + description: 'descriptions', + order: 0, + }; + }, + }) + ).toThrowError(); +}); diff --git a/src/plugins/content_management/public/services/content_management/content_management_service.ts b/src/plugins/content_management/public/services/content_management/content_management_service.ts new file mode 100644 index 000000000000..82ce4640c4fc --- /dev/null +++ b/src/plugins/content_management/public/services/content_management/content_management_service.ts @@ -0,0 +1,62 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Page } from './page'; +import { ContentProvider, PageConfig } from './types'; + +export class ContentManagementService { + contentProviders: Map = new Map(); + pages: Map = new Map(); + constructor() {} + + registerPage = (pageConfig: PageConfig) => { + if (this.pages.has(pageConfig.id)) { + throw new Error(`Page id exists: ${pageConfig.id}`); + } + + const page = new Page(pageConfig); + this.pages.set(pageConfig.id, page); + + if (pageConfig.sections) { + pageConfig.sections.forEach((section) => { + page.createSection(section); + }); + } + + return page; + }; + + getPage = (id: string) => { + return this.pages.get(id); + }; + + registerContentProvider = (provider: ContentProvider) => { + if (this.contentProviders.get(provider.id)) { + throw new Error(`Cannot register content provider with the same id ${provider.id}`); + } + + this.contentProviders.set(provider.id, provider); + + const targetArea = provider.getTargetArea(); + const [pageId, sectionId] = targetArea.split('/'); + + if (!pageId || !sectionId) { + throw new Error('getTargetArea() should return a string in format {pageId}/{sectionId}'); + } + + const page = this.getPage(pageId); + if (page) { + page.addContent(sectionId, provider.getContent()); + } + }; + + setup() { + return {}; + } + + start() { + return {}; + } +} diff --git a/src/plugins/content_management/public/services/content_management/index.ts b/src/plugins/content_management/public/services/content_management/index.ts new file mode 100644 index 000000000000..ab6d8357d9b5 --- /dev/null +++ b/src/plugins/content_management/public/services/content_management/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './content_management_service'; +export * from './page'; +export * from './types'; diff --git a/src/plugins/content_management/public/services/content_management/page.test.ts b/src/plugins/content_management/public/services/content_management/page.test.ts new file mode 100644 index 000000000000..5ce36fb21f5a --- /dev/null +++ b/src/plugins/content_management/public/services/content_management/page.test.ts @@ -0,0 +1,104 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Page } from './page'; + +test('it should create a Page instance', () => { + const page = new Page({ id: 'page1' }); + expect(page.config).toEqual({ id: 'page1' }); +}); + +test('it should create sections', () => { + const page = new Page({ id: 'page1' }); + page.createSection({ id: 'section1', kind: 'dashboard', order: 2000 }); + page.createSection({ id: 'section2', kind: 'dashboard', order: 1000 }); + expect(page.getSections()).toHaveLength(2); +}); + +test('it should not create section with existing id', () => { + const page = new Page({ id: 'page1' }); + page.createSection({ id: 'section1', kind: 'dashboard', order: 2000 }); + expect(() => + page.createSection({ id: 'section1', kind: 'dashboard', order: 1000 }) + ).toThrowError(); +}); + +test('it should return sections in order', () => { + const page = new Page({ id: 'page1' }); + page.createSection({ id: 'section1', kind: 'dashboard', order: 2000 }); + page.createSection({ id: 'section2', kind: 'dashboard', order: 1000 }); + expect(page.getSections()).toEqual([ + { id: 'section2', kind: 'dashboard', order: 1000 }, + { id: 'section1', kind: 'dashboard', order: 2000 }, + ]); + expect(page.getSections$().value).toEqual([ + { id: 'section2', kind: 'dashboard', order: 1000 }, + { id: 'section1', kind: 'dashboard', order: 2000 }, + ]); +}); + +test('it should add contents to section', () => { + const page = new Page({ id: 'page1' }); + page.createSection({ id: 'section1', kind: 'dashboard', order: 2000 }); + page.addContent('section1', { + id: 'content1', + kind: 'visualization', + order: 10, + input: { kind: 'static', id: 'viz-id-1' }, + }); + page.addContent('section1', { + id: 'content2', + kind: 'visualization', + order: 5, + input: { kind: 'static', id: 'viz-id-2' }, + }); + expect(page.getContents('section1')).toHaveLength(2); +}); + +test('it should return contents in order', () => { + const page = new Page({ id: 'page1' }); + page.createSection({ id: 'section1', kind: 'dashboard', order: 2000 }); + page.addContent('section1', { + id: 'content1', + kind: 'visualization', + order: 10, + input: { kind: 'static', id: 'viz-id-1' }, + }); + page.addContent('section1', { + id: 'content2', + kind: 'visualization', + order: 5, + input: { kind: 'static', id: 'viz-id-2' }, + }); + expect(page.getContents('section1')).toEqual([ + { + id: 'content2', + kind: 'visualization', + order: 5, + input: { kind: 'static', id: 'viz-id-2' }, + }, + { + id: 'content1', + kind: 'visualization', + order: 10, + input: { kind: 'static', id: 'viz-id-1' }, + }, + ]); + + expect(page.getContents$('section1').value).toEqual([ + { + id: 'content2', + kind: 'visualization', + order: 5, + input: { kind: 'static', id: 'viz-id-2' }, + }, + { + id: 'content1', + kind: 'visualization', + order: 10, + input: { kind: 'static', id: 'viz-id-1' }, + }, + ]); +}); diff --git a/src/plugins/content_management/public/services/content_management/page.ts b/src/plugins/content_management/public/services/content_management/page.ts new file mode 100644 index 000000000000..fea90e57f037 --- /dev/null +++ b/src/plugins/content_management/public/services/content_management/page.ts @@ -0,0 +1,67 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { BehaviorSubject } from 'rxjs'; +import { Content, PageConfig, Section } from './types'; + +export class Page { + config: PageConfig; + private sections: Map = new Map(); + private contents: Map = new Map(); + private sections$ = new BehaviorSubject([]); + private contentObservables: Map> = new Map(); + private NO_CONTENT$ = new BehaviorSubject([]); + + constructor(pageConfig: PageConfig) { + this.config = pageConfig; + } + + createSection(section: Section) { + if (this.sections.has(section.id)) { + throw new Error(`Section id exists: ${section.id}`); + } + this.sections.set(section.id, section); + this.sections$.next(this.getSections()); + } + + getSections() { + return [...this.sections.values()].sort((a, b) => a.order - b.order); + } + + getSections$() { + return this.sections$; + } + + addContent(sectionId: string, content: Content) { + const sectionContents = this.contents.get(sectionId); + if (sectionContents) { + if (content.kind === 'dashboard' && sectionContents.length > 0) { + throw new Error('Section type "dashboard" can only have one content type of "dashboard"'); + } + sectionContents.push(content); + // sort content by order + sectionContents.sort((a, b) => a.order - b.order); + } else { + this.contents.set(sectionId, [content]); + } + + if (this.contentObservables.get(sectionId)) { + this.contentObservables.get(sectionId)?.next(this.contents.get(sectionId) ?? []); + } else { + this.contentObservables.set( + sectionId, + new BehaviorSubject(this.contents.get(sectionId) ?? []) + ); + } + } + + getContents(sectionId: string) { + return this.contents.get(sectionId) ?? []; + } + + getContents$(sectionId: string) { + return this.contentObservables.get(sectionId) ?? this.NO_CONTENT$; + } +} diff --git a/src/plugins/content_management/public/services/content_management/types.ts b/src/plugins/content_management/public/services/content_management/types.ts new file mode 100644 index 000000000000..0a0020ed6254 --- /dev/null +++ b/src/plugins/content_management/public/services/content_management/types.ts @@ -0,0 +1,84 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface PageConfig { + id: string; + title?: string; + description?: string; + sections?: Section[]; +} + +export type Section = + | { + kind: 'custom'; + id: string; + order: number; + title?: string; + description?: string; + render: (contents: Content[]) => JSX.Element; + } + | { + kind: 'dashboard'; + id: string; + order: number; + title?: string; + description?: string; + } + | { + kind: 'card'; + id: string; + order: number; + title?: string; + }; + +export type Content = + | { + kind: 'visualization'; + id: string; + order: number; + input: SavedObjectInput; + } + | { + kind: 'dashboard'; + id: string; + order: number; + input: SavedObjectInput; + } + | { + kind: 'custom'; + id: string; + order: number; + render: () => JSX.Element; + } + | { + kind: 'card'; + id: string; + order: number; + title: string; + description: string; + onClick?: () => void; + }; + +export type SavedObjectInput = + | { + kind: 'static'; + /** + * The visualization id + */ + id: string; + } + | { + kind: 'dynamic'; + /** + * A promise that returns a visualization id + */ + get: () => Promise; + }; + +export interface ContentProvider { + id: string; + getContent: () => Content; + getTargetArea: () => string; +} diff --git a/src/plugins/content_management/public/services/index.ts b/src/plugins/content_management/public/services/index.ts new file mode 100644 index 000000000000..55bc487558c8 --- /dev/null +++ b/src/plugins/content_management/public/services/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './content_management'; diff --git a/src/plugins/content_management/public/types.ts b/src/plugins/content_management/public/types.ts new file mode 100644 index 000000000000..697ad4d3829a --- /dev/null +++ b/src/plugins/content_management/public/types.ts @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { CoreStart } from 'opensearch-dashboards/public'; + +import { ContentManagementService, ContentProvider } from './services'; +import { EmbeddableSetup, EmbeddableStart } from '../../embeddable/public'; + +export interface ContentManagementPluginSetup { + registerPage: ContentManagementService['registerPage']; +} +export interface ContentManagementPluginStart { + /** + * @experimental this API is experimental and might change in future releases + */ + registerContentProvider: (provider: ContentProvider) => void; + renderPage: (id: string) => React.ReactNode; +} + +export interface ContentManagementPluginStartDependencies { + embeddable: EmbeddableStart; +} + +export interface ContentManagementPluginSetupDependencies { + embeddable: EmbeddableSetup; +} + +export type ContentServices = CoreStart & ContentManagementPluginStartDependencies; diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_root.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable_root.tsx index be047f8a9698..17b9ca8f6a10 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable_root.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_root.tsx @@ -43,6 +43,7 @@ interface Props { export class EmbeddableRoot extends React.Component { private root?: React.RefObject; private alreadyMounted: boolean = false; + private lastUsedInput?: EmbeddableInput; constructor(props: Props) { super(props); @@ -54,6 +55,7 @@ export class EmbeddableRoot extends React.Component { if (this.root && this.root.current && this.props.embeddable) { this.alreadyMounted = true; this.props.embeddable.render(this.root.current); + this.lastUsedInput = this.props.input; } } @@ -62,6 +64,16 @@ export class EmbeddableRoot extends React.Component { if (this.root && this.root.current && this.props.embeddable && !this.alreadyMounted) { this.alreadyMounted = true; this.props.embeddable.render(this.root.current); + /** + * When an embeddable was created with an value asynchronously, at the time when calling embeddable.render() + * The current input value might already changed, so it needs to call embeddable.updateInput() with the + * latest input here. It cannot simply compare prevProps.input and this.props.input because input may already + * be changed before embeddable was created. + */ + if (this.lastUsedInput !== this.props.input && this.props.input) { + this.props.embeddable.updateInput(this.props.input); + this.lastUsedInput = this.props.input; + } justRendered = true; } @@ -72,9 +84,10 @@ export class EmbeddableRoot extends React.Component { this.props.embeddable && this.alreadyMounted && this.props.input && - prevProps?.input !== this.props.input + this.lastUsedInput !== this.props.input ) { this.props.embeddable.updateInput(this.props.input); + this.lastUsedInput = this.props.input; } } diff --git a/src/plugins/home/common/constants.ts b/src/plugins/home/common/constants.ts index 25c78c59c4ac..6d5c74267be0 100644 --- a/src/plugins/home/common/constants.ts +++ b/src/plugins/home/common/constants.ts @@ -32,3 +32,15 @@ export const PLUGIN_ID = 'home'; export const HOME_APP_BASE_PATH = `/app/${PLUGIN_ID}`; export const USE_NEW_HOME_PAGE = 'home:useNewHomePage'; export const IMPORT_SAMPLE_DATA_APP_ID = 'import_sample_data'; +export const HOME_PAGE_ID = 'osd_homepage'; +export enum SECTIONS { + GET_STARTED = `get_started`, + SERVICE_CARDS = `service_cards`, + RECENTLY_VIEWED = `recently_viewed`, +} + +export enum HOME_CONTENT_AREAS { + GET_STARTED = `${HOME_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${HOME_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} diff --git a/src/plugins/home/opensearch_dashboards.json b/src/plugins/home/opensearch_dashboards.json index 7dc3adf0d2c7..e96b2bee998d 100644 --- a/src/plugins/home/opensearch_dashboards.json +++ b/src/plugins/home/opensearch_dashboards.json @@ -3,7 +3,7 @@ "version": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["data", "urlForwarding", "savedObjects"], + "requiredPlugins": ["data", "urlForwarding", "savedObjects", "contentManagement"], "optionalPlugins": ["usageCollection", "telemetry", "dataSource"], "requiredBundles": ["opensearchDashboardsReact", "dataSourceManagement"] } diff --git a/src/plugins/home/public/application/components/home_app.js b/src/plugins/home/public/application/components/home_app.js index 4febddb9148d..4eb253a9cdd0 100644 --- a/src/plugins/home/public/application/components/home_app.js +++ b/src/plugins/home/public/application/components/home_app.js @@ -32,7 +32,6 @@ import React from 'react'; import { I18nProvider } from '@osd/i18n/react'; import PropTypes from 'prop-types'; import { Home } from './legacy/home'; -import { Homepage } from './homepage'; import { FeatureDirectory } from './feature_directory'; import { TutorialDirectory } from './tutorial_directory'; import { Tutorial } from './tutorial/tutorial'; @@ -41,7 +40,7 @@ import { getTutorial } from '../load_tutorials'; import { replaceTemplateStrings } from './tutorial/replace_template_strings'; import { getServices } from '../opensearch_dashboards_services'; import { useMount } from 'react-use'; -import { USE_NEW_HOME_PAGE } from '../../../common/constants'; +import { USE_NEW_HOME_PAGE, HOME_PAGE_ID } from '../../../common/constants'; const RedirectToDefaultApp = () => { useMount(() => { @@ -88,6 +87,7 @@ export function HomeApp({ directories, solutions }) { environmentService, telemetry, uiSettings, + contentManagement, } = getServices(); const environment = environmentService.getEnvironment(); const isCloudEnabled = environment.cloud; @@ -117,7 +117,7 @@ export function HomeApp({ directories, solutions }) { /> ); - const homepage = ; + const homepage = contentManagement.renderPage(HOME_PAGE_ID); return ( diff --git a/src/plugins/home/public/application/home_render.tsx b/src/plugins/home/public/application/home_render.tsx new file mode 100644 index 000000000000..49d5bd1c9043 --- /dev/null +++ b/src/plugins/home/public/application/home_render.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { + ContentManagementPluginSetup, + ContentManagementPluginStart, +} from '../../../../plugins/content_management/public'; +import { HOME_PAGE_ID, SECTIONS } from '../../common/constants'; + +export const setupHome = (contentManagement: ContentManagementPluginSetup) => { + contentManagement.registerPage({ + id: HOME_PAGE_ID, + title: 'Home', + sections: [ + { + id: SECTIONS.SERVICE_CARDS, + order: 3000, + kind: 'dashboard', + }, + { + id: SECTIONS.RECENTLY_VIEWED, + order: 2000, + title: 'Recently viewed', + kind: 'custom', + render: () => <>, + }, + { + id: SECTIONS.GET_STARTED, + order: 1000, + title: 'Define your path forward with OpenSearch', + kind: 'card', + }, + ], + }); +}; + +export const initHome = (contentManagement: ContentManagementPluginStart, core: CoreStart) => {}; diff --git a/src/plugins/home/public/application/opensearch_dashboards_services.mock.ts b/src/plugins/home/public/application/opensearch_dashboards_services.mock.ts index b06d03cbc105..cbe172206867 100644 --- a/src/plugins/home/public/application/opensearch_dashboards_services.mock.ts +++ b/src/plugins/home/public/application/opensearch_dashboards_services.mock.ts @@ -13,6 +13,7 @@ import { TutorialService, } from '../services'; import { telemetryPluginMock } from '../../../telemetry/public/mocks'; +import { contentManagementPluginMocks } from '../../../content_management/public'; export const getMockedServices = () => { const coreMocks = coreMock.createStart(); @@ -43,5 +44,6 @@ export const getMockedServices = () => { homeConfig: homePlugin.config, featureCatalogue: new FeatureCatalogueRegistry(), sectionTypes: new SectionTypeService(), + contentManagement: contentManagementPluginMocks.createStartContract(), }; }; diff --git a/src/plugins/home/public/application/opensearch_dashboards_services.ts b/src/plugins/home/public/application/opensearch_dashboards_services.ts index 727cb03c10ab..1107e46ecf2e 100644 --- a/src/plugins/home/public/application/opensearch_dashboards_services.ts +++ b/src/plugins/home/public/application/opensearch_dashboards_services.ts @@ -48,6 +48,7 @@ import { SectionTypeService } from '../services/section_type'; import { ConfigSchema } from '../../config'; import { HomePluginBranding } from '..'; import { DataSourcePluginStart } from '../../../data_source/public'; +import { ContentManagementPluginStart } from '../../../content_management/public'; export interface HomeOpenSearchDashboardsServices { indexPatternService: any; @@ -56,6 +57,7 @@ export interface HomeOpenSearchDashboardsServices { application: ApplicationStart; uiSettings: IUiSettingsClient; urlForwarding: UrlForwardingStart; + contentManagement: ContentManagementPluginStart; homeConfig: ConfigSchema; featureCatalogue: FeatureCatalogueRegistry; http: HttpStart; diff --git a/src/plugins/home/public/plugin.test.ts b/src/plugins/home/public/plugin.test.ts index 62ab89dce847..f7bfec0cafc0 100644 --- a/src/plugins/home/public/plugin.test.ts +++ b/src/plugins/home/public/plugin.test.ts @@ -32,6 +32,7 @@ import { registryMock, environmentMock, tutorialMock, sectionTypeMock } from './ import { HomePublicPlugin } from './plugin'; import { coreMock } from '../../../core/public/mocks'; import { urlForwardingPluginMock } from '../../url_forwarding/public/mocks'; +import { contentManagementPluginMocks } from 'src/plugins/content_management/public'; const mockInitializerContext = coreMock.createPluginInitializerContext(); @@ -50,6 +51,7 @@ describe('HomePublicPlugin', () => { coreMock.createSetup() as any, { urlForwarding: urlForwardingPluginMock.createSetupContract(), + contentManagement: contentManagementPluginMocks.createSetupContract(), } ); expect(setup).toHaveProperty('featureCatalogue'); @@ -69,6 +71,7 @@ describe('HomePublicPlugin', () => { coreMock.createSetup() as any, { urlForwarding: urlForwardingPluginMock.createSetupContract(), + contentManagement: contentManagementPluginMocks.createSetupContract(), } ); expect(setup).toHaveProperty('featureCatalogue'); @@ -80,6 +83,7 @@ describe('HomePublicPlugin', () => { coreMock.createSetup() as any, { urlForwarding: urlForwardingPluginMock.createSetupContract(), + contentManagement: contentManagementPluginMocks.createSetupContract(), } ); expect(setup).toHaveProperty('environment'); @@ -91,6 +95,7 @@ describe('HomePublicPlugin', () => { coreMock.createSetup() as any, { urlForwarding: urlForwardingPluginMock.createSetupContract(), + contentManagement: contentManagementPluginMocks.createSetupContract(), } ); expect(setup).toHaveProperty('tutorials'); @@ -101,6 +106,7 @@ describe('HomePublicPlugin', () => { const coreMocks = coreMock.createSetup(); await new HomePublicPlugin(mockInitializerContext).setup(coreMocks, { urlForwarding: urlForwardingPluginMock.createSetupContract(), + contentManagement: contentManagementPluginMocks.createSetupContract(), }); expect(coreMocks.application.register).toBeCalledTimes(2); }); diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index 3256963d6c0a..fe1099a8e635 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -65,17 +65,24 @@ import { DataSourcePluginStart } from '../../data_source/public'; import { workWithDataSection } from './application/components/homepage/sections/work_with_data'; import { learnBasicsSection } from './application/components/homepage/sections/learn_basics'; import { DEFAULT_NAV_GROUPS } from '../../../core/public'; +import { + ContentManagementPluginSetup, + ContentManagementPluginStart, +} from '../../content_management/public'; +import { initHome, setupHome } from './application/home_render'; export interface HomePluginStartDependencies { data: DataPublicPluginStart; telemetry?: TelemetryPluginStart; urlForwarding: UrlForwardingStart; dataSource?: DataSourcePluginStart; + contentManagement: ContentManagementPluginStart; } export interface HomePluginSetupDependencies { usageCollection?: UsageCollectionSetup; urlForwarding: UrlForwardingSetup; + contentManagement: ContentManagementPluginSetup; } export class HomePublicPlugin @@ -95,7 +102,7 @@ export class HomePublicPlugin public setup( core: CoreSetup, - { urlForwarding, usageCollection }: HomePluginSetupDependencies + { urlForwarding, usageCollection, contentManagement }: HomePluginSetupDependencies ): HomePublicPluginSetup { const setCommonService = async ( homeOpenSearchDashboardsServices?: Partial @@ -105,7 +112,13 @@ export class HomePublicPlugin : () => {}; const [ coreStart, - { telemetry, data, urlForwarding: urlForwardingStart, dataSource }, + { + telemetry, + data, + urlForwarding: urlForwardingStart, + dataSource, + contentManagement: contentManagementStart, + }, ] = await core.getStartServices(); setServices({ trackUiMetric, @@ -124,6 +137,7 @@ export class HomePublicPlugin indexPatternService: data.indexPatterns, environmentService: this.environmentService, urlForwarding: urlForwardingStart, + contentManagement: contentManagementStart, homeConfig: this.initializerContext.config.get(), tutorialService: this.tutorialService, featureCatalogue: this.featuresCatalogueRegistry, @@ -133,6 +147,7 @@ export class HomePublicPlugin ...homeOpenSearchDashboardsServices, }); }; + core.application.register({ id: PLUGIN_ID, title: 'Home', @@ -200,6 +215,7 @@ export class HomePublicPlugin sectionTypes.registerSection(workWithDataSection); sectionTypes.registerSection(learnBasicsSection); + setupHome(contentManagement); return { featureCatalogue, @@ -209,12 +225,18 @@ export class HomePublicPlugin }; } - public start(core: CoreStart, { data, urlForwarding }: HomePluginStartDependencies) { + public start( + core: CoreStart, + { data, urlForwarding, contentManagement }: HomePluginStartDependencies + ) { const { application: { capabilities, currentAppId$ }, http, } = core; + // initialize homepage + initHome(contentManagement, core); + this.featuresCatalogueRegistry.start({ capabilities }); this.sectionTypeService.start({ core, data }); From 200a5c3d5716771a868695fe8e9d35a9ee0e2f8b Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:45:39 +0800 Subject: [PATCH 090/276] [navigation-next] feat: update category (#7339) (#7340) (#7343) * feat: update category * Changeset file for PR #7339 created/updated --------- (cherry picked from commit d4d1f7700b29a1b5af211585cf9338b8a2ba2748) (cherry picked from commit 54cbaaa3e086cac4675ab733a91bc2d1abad8f5a) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7339.yml | 2 ++ src/core/utils/default_app_categories.ts | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/7339.yml diff --git a/changelogs/fragments/7339.yml b/changelogs/fragments/7339.yml new file mode 100644 index 000000000000..23f897df941d --- /dev/null +++ b/changelogs/fragments/7339.yml @@ -0,0 +1,2 @@ +feat: +- [navigation-next] update category ([#7339](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7339)) \ No newline at end of file diff --git a/src/core/utils/default_app_categories.ts b/src/core/utils/default_app_categories.ts index d22dbaf1b7ac..f274cecf2cda 100644 --- a/src/core/utils/default_app_categories.ts +++ b/src/core/utils/default_app_categories.ts @@ -80,19 +80,20 @@ export const DEFAULT_APP_CATEGORIES: Record = Object.freeze }), order: 1000, }, + // TODO remove this default category dashboardAndReport: { id: 'visualizeAndReport', label: i18n.translate('core.ui.visualizeAndReport.label', { defaultMessage: 'Visualize and report', }), - order: 2000, + order: 3000, }, visualizeAndReport: { id: 'visualizeAndReport', label: i18n.translate('core.ui.visualizeAndReport.label', { defaultMessage: 'Visualize and report', }), - order: 2000, + order: 3000, }, analyzeSearch: { id: 'analyzeSearch', @@ -101,12 +102,20 @@ export const DEFAULT_APP_CATEGORIES: Record = Object.freeze }), order: 4000, }, + // TODO remove this default category detect: { - id: 'detect', - label: i18n.translate('core.ui.detect.label', { - defaultMessage: 'Detect', + id: 'configure', + label: i18n.translate('core.ui.configure.label', { + defaultMessage: 'Configure', }), - order: 3000, + order: 2000, + }, + configure: { + id: 'configure', + label: i18n.translate('core.ui.configure.label', { + defaultMessage: 'Configure', + }), + order: 2000, }, manage: { id: 'manage', From 4963000922881d100ab548d07d242ce635768c2a Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:46:46 +0800 Subject: [PATCH 091/276] [Navigation] Update dev tools tab css for new left navigation (#7328) (#7334) * update dev tools tab css * Changeset file for PR #7328 created/updated --------- (cherry picked from commit 4c619067f2d1f85afd9ad3f67af15d8f42c3e4da) Signed-off-by: Shenoy Pratik Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7328.yml | 2 ++ src/plugins/dev_tools/public/index.scss | 6 ------ 2 files changed, 2 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/7328.yml diff --git a/changelogs/fragments/7328.yml b/changelogs/fragments/7328.yml new file mode 100644 index 000000000000..2e2f63275d8b --- /dev/null +++ b/changelogs/fragments/7328.yml @@ -0,0 +1,2 @@ +fix: +- [Navigation] Update dev tools tab css for new left navigation ([#7328](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7328)) \ No newline at end of file diff --git a/src/plugins/dev_tools/public/index.scss b/src/plugins/dev_tools/public/index.scss index 56d7bc9c11c1..554452a8923e 100644 --- a/src/plugins/dev_tools/public/index.scss +++ b/src/plugins/dev_tools/public/index.scss @@ -26,9 +26,3 @@ margin: 7px 8px 0 0; min-width: 400px; } - -.devAppTabs { - display: flex; - flex-flow: row wrap; - justify-content: space-between; -} From ab97c6a29b0de64a566f417ab2e32d07d6c46429 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 14:12:26 +0800 Subject: [PATCH 092/276] [admin] add Viraj to be a maintainer (#7196) (#7199) * [admin] add Viraj to be a maintainer * Changeset file for PR #7196 created/updated --------- (cherry picked from commit 778a84596e559bf5c67de7b53f465cc251a85f5d) Signed-off-by: Kawika Avilla Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- .github/CODEOWNERS | 2 +- MAINTAINERS.md | 3 ++- changelogs/fragments/7196.yml | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/7196.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 46a7e5f26b84..5f39327d54b5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @ananzh @kavilla @AMoo-Miki @ashwin-pc @joshuarrrr @abbyhu2000 @zengyan-amazon @zhongnansu @manasvinibs @ZilongX @Flyingliuhub @curq @bandinib-amzn @SuZhou-Joe @ruanyl @BionIT @xinruiba @zhyuanqi @mengweieric @LDrago27 +* @ananzh @kavilla @AMoo-Miki @ashwin-pc @joshuarrrr @abbyhu2000 @zengyan-amazon @zhongnansu @manasvinibs @ZilongX @Flyingliuhub @curq @bandinib-amzn @SuZhou-Joe @ruanyl @BionIT @xinruiba @zhyuanqi @mengweieric @LDrago27 @virajsanghvi diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 205c72ed327f..0f6c888dd926 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -25,7 +25,8 @@ This document contains a list of maintainers in this repo. See [opensearch-proje | Xinrui Bai | [xinruiba](https://github.com/xinruiba) | Amazon | | Ella Zhu | [zhyuanqi](https://github.com/zhyuanqi) | Amazon | | Eric Wei | [mengweieric](https://github.com/mengweieric) | Amazon | -| Suchit Sahoo | [LDrago27](https://github.com/LDrago27) | Amazon | +| Suchit Sahoo | [LDrago27](https://github.com/LDrago27) | Amazon | +| Viraj Sanghvi | [virajsanghvi](https://github.com/virajsanghvi) | Amazon | ## Emeritus diff --git a/changelogs/fragments/7196.yml b/changelogs/fragments/7196.yml new file mode 100644 index 000000000000..d4b0bae39894 --- /dev/null +++ b/changelogs/fragments/7196.yml @@ -0,0 +1,2 @@ +doc: +- Add Viraj as maintainer ([#7196](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7196)) \ No newline at end of file From b13f59f7a45338a3cfe9d2f08c45d844c02a6d13 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 15:05:43 +0800 Subject: [PATCH 093/276] [Workspace] Register four get started cards in home page (#7333) (#7344) * support get start card in home page * Changeset file for PR #7333 created/updated * fix unit test errors * optimize the code --------- (cherry picked from commit 08c2a006fa47b614215cf9364f7161fc55b2b429) Signed-off-by: yubonluo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7333.yml | 2 + .../card_container/card_container.tsx | 7 +- .../card_container/card_embeddable.test.tsx | 9 +- .../card_container/card_embeddable.tsx | 10 +- .../public/components/page_render.tsx | 25 +- .../public/components/section_input.ts | 2 + .../public/components/section_render.tsx | 27 ++- .../services/content_management/types.ts | 2 + src/plugins/home/public/index.ts | 2 + .../workspace/opensearch_dashboards.json | 4 +- .../components/home_get_start_card/index.ts | 6 + .../use_case_footer.test.tsx | 156 +++++++++++++ .../home_get_start_card/use_case_footer.tsx | 219 ++++++++++++++++++ .../workspace_menu/workspace_menu.test.tsx | 12 - .../workspace_menu/workspace_menu.tsx | 12 +- src/plugins/workspace/public/plugin.test.ts | 22 +- src/plugins/workspace/public/plugin.ts | 52 ++++- 17 files changed, 522 insertions(+), 47 deletions(-) create mode 100644 changelogs/fragments/7333.yml create mode 100644 src/plugins/workspace/public/components/home_get_start_card/index.ts create mode 100644 src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx create mode 100644 src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx diff --git a/changelogs/fragments/7333.yml b/changelogs/fragments/7333.yml new file mode 100644 index 000000000000..09d225d51ca2 --- /dev/null +++ b/changelogs/fragments/7333.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace] Register four get started cards in home page ([#7333](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7333)) \ No newline at end of file diff --git a/src/plugins/content_management/public/components/card_container/card_container.tsx b/src/plugins/content_management/public/components/card_container/card_container.tsx index 518734563607..f3784f1f5fc4 100644 --- a/src/plugins/content_management/public/components/card_container/card_container.tsx +++ b/src/plugins/content_management/public/components/card_container/card_container.tsx @@ -10,7 +10,12 @@ import { CardList } from './card_list'; export const CARD_CONTAINER = 'CARD_CONTAINER'; -export type CardContainerInput = ContainerInput<{ description: string; onClick?: () => void }>; +export type CardContainerInput = ContainerInput<{ + description: string; + onClick?: () => void; + getIcon?: () => React.ReactElement; + getFooter?: () => React.ReactElement; +}>; export class CardContainer extends Container<{}, CardContainerInput> { public readonly type = CARD_CONTAINER; diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx index b335bac6d996..a87cd43554ea 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx @@ -3,10 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ +import React from 'react'; import { CardEmbeddable } from './card_embeddable'; test('CardEmbeddable should render a card with the title', () => { - const embeddable = new CardEmbeddable({ id: 'card-id', title: 'card title', description: '' }); + const embeddable = new CardEmbeddable({ + id: 'card-id', + title: 'card title', + description: '', + getIcon: () => <>icon, + getFooter: () => <>footer, + }); const node = document.createElement('div'); embeddable.render(node); diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx index 844cf13a777c..0e7b6b2c82e5 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx @@ -10,7 +10,12 @@ import { EuiCard } from '@elastic/eui'; import { Embeddable, EmbeddableInput, IContainer } from '../../../../embeddable/public'; export const CARD_EMBEDDABLE = 'card_embeddable'; -export type CardEmbeddableInput = EmbeddableInput & { description: string; onClick?: () => void }; +export type CardEmbeddableInput = EmbeddableInput & { + description: string; + onClick?: () => void; + getIcon: () => React.ReactElement; + getFooter: () => React.ReactElement; +}; export class CardEmbeddable extends Embeddable { public readonly type = CARD_EMBEDDABLE; @@ -27,10 +32,13 @@ export class CardEmbeddable extends Embeddable { this.node = node; ReactDOM.render( , node ); diff --git a/src/plugins/content_management/public/components/page_render.tsx b/src/plugins/content_management/public/components/page_render.tsx index 9a5211ca3a46..90d6033576bb 100644 --- a/src/plugins/content_management/public/components/page_render.tsx +++ b/src/plugins/content_management/public/components/page_render.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { useObservable } from 'react-use'; import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { Page } from '../services'; import { SectionRender } from './section_render'; import { EmbeddableStart } from '../../../embeddable/public'; @@ -21,16 +22,22 @@ export const PageRender = ({ page, embeddable, savedObjectsClient }: Props) => { const sections = useObservable(page.getSections$()) || []; return ( -
+ {sections.map((section) => ( - + + + ))} -
+ ); }; diff --git a/src/plugins/content_management/public/components/section_input.ts b/src/plugins/content_management/public/components/section_input.ts index 1d37feef8ecc..00bb5b0683c7 100644 --- a/src/plugins/content_management/public/components/section_input.ts +++ b/src/plugins/content_management/public/components/section_input.ts @@ -42,6 +42,8 @@ export const createCardInput = ( title: content.title, description: content.description, onClick: content.onClick, + getIcon: content?.getIcon, + getFooter: content?.getFooter, }, }; } diff --git a/src/plugins/content_management/public/components/section_render.tsx b/src/plugins/content_management/public/components/section_render.tsx index 19f14bdb1d67..d28fbad7296a 100644 --- a/src/plugins/content_management/public/components/section_render.tsx +++ b/src/plugins/content_management/public/components/section_render.tsx @@ -6,9 +6,8 @@ import React, { useState, useEffect, useMemo } from 'react'; import { useObservable } from 'react-use'; import { BehaviorSubject } from 'rxjs'; -import { EuiTitle } from '@elastic/eui'; +import { EuiButtonIcon, EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; - import { Content, Section } from '../services'; import { EmbeddableInput, EmbeddableRenderer, EmbeddableStart } from '../../../embeddable/public'; import { DashboardContainerInput } from '../../../dashboard/public'; @@ -49,6 +48,10 @@ const DashboardSection = ({ section, embeddable, contents$, savedObjectsClient } }; const CardSection = ({ section, embeddable, contents$ }: Props) => { + const [isCardVisible, setIsCardVisible] = useState(true); + const toggleCardVisibility = () => { + setIsCardVisible(!isCardVisible); + }; const contents = useObservable(contents$); const input = useMemo(() => { return createCardInput(section, contents ?? []); @@ -58,12 +61,24 @@ const CardSection = ({ section, embeddable, contents$ }: Props) => { if (section.kind === 'card' && factory && input) { return ( -
+ -

{section.title}

+

+ + {section.title} +

- -
+ {isCardVisible && ( + <> + + + )} + ); } diff --git a/src/plugins/content_management/public/services/content_management/types.ts b/src/plugins/content_management/public/services/content_management/types.ts index 0a0020ed6254..55da19f26b87 100644 --- a/src/plugins/content_management/public/services/content_management/types.ts +++ b/src/plugins/content_management/public/services/content_management/types.ts @@ -59,6 +59,8 @@ export type Content = title: string; description: string; onClick?: () => void; + getIcon?: () => React.ReactElement; + getFooter?: () => React.ReactElement; }; export type SavedObjectInput = diff --git a/src/plugins/home/public/index.ts b/src/plugins/home/public/index.ts index 58ad10cdf04b..d252a31a0977 100644 --- a/src/plugins/home/public/index.ts +++ b/src/plugins/home/public/index.ts @@ -53,3 +53,5 @@ import { HomePublicPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => new HomePublicPlugin(initializerContext); + +export { HOME_PAGE_ID, HOME_CONTENT_AREAS } from '../common/constants'; diff --git a/src/plugins/workspace/opensearch_dashboards.json b/src/plugins/workspace/opensearch_dashboards.json index 2e9377b3bda9..99a66fb1743a 100644 --- a/src/plugins/workspace/opensearch_dashboards.json +++ b/src/plugins/workspace/opensearch_dashboards.json @@ -7,6 +7,6 @@ "savedObjects", "opensearchDashboardsReact" ], - "optionalPlugins": ["savedObjectsManagement","management","dataSourceManagement"], - "requiredBundles": ["opensearchDashboardsReact"] + "optionalPlugins": ["savedObjectsManagement","management","dataSourceManagement","contentManagement"], + "requiredBundles": ["opensearchDashboardsReact", "home"] } diff --git a/src/plugins/workspace/public/components/home_get_start_card/index.ts b/src/plugins/workspace/public/components/home_get_start_card/index.ts new file mode 100644 index 000000000000..f78300a492d3 --- /dev/null +++ b/src/plugins/workspace/public/components/home_get_start_card/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { UseCaseFooter } from './use_case_footer'; diff --git a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx new file mode 100644 index 000000000000..8296a5ba8359 --- /dev/null +++ b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx @@ -0,0 +1,156 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { UseCaseFooter as UseCaseFooterComponent, UseCaseFooterProps } from './use_case_footer'; +import { coreMock, httpServiceMock } from '../../../../../core/public/mocks'; +import { IntlProvider } from 'react-intl'; +import { WorkspaceUseCase } from '../../types'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { BehaviorSubject } from 'rxjs'; +import { WORKSPACE_USE_CASES } from '../../../common/constants'; + +describe('UseCaseFooter', () => { + // let coreStartMock: CoreStart; + const navigateToApp = jest.fn(); + const registeredUseCases$ = new BehaviorSubject([ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.analytics, + WORKSPACE_USE_CASES.search, + ]); + + const getMockCore = (isDashboardAdmin: boolean = true) => { + const coreStartMock = coreMock.createStart(); + coreStartMock.application.capabilities = { + ...coreStartMock.application.capabilities, + dashboards: { isDashboardAdmin }, + }; + coreStartMock.application = { + ...coreStartMock.application, + navigateToApp, + }; + jest.spyOn(coreStartMock.application, 'getUrlForApp').mockImplementation((appId: string) => { + return `https://test.com/app/${appId}`; + }); + return coreStartMock; + }; + + afterEach(() => { + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + const UseCaseFooter = (props: UseCaseFooterProps) => { + return ( + + + + ); + }; + it('renders create workspace button for admin when no workspaces within use case exist', () => { + const { getByTestId } = render( + + ); + + const button = getByTestId('useCase.footer.createWorkspace.button'); + expect(button).toBeInTheDocument(); + fireEvent.click(button); + const createWorkspaceButtonInModal = getByTestId('useCase.footer.modal.create.button'); + expect(createWorkspaceButtonInModal).toHaveAttribute( + 'href', + 'https://test.com/app/workspace_create' + ); + }); + + it('renders create workspace button for non-admin when no workspaces within use case exist', () => { + const { getByTestId } = render( + + ); + + const button = getByTestId('useCase.footer.createWorkspace.button'); + expect(button).toBeInTheDocument(); + fireEvent.click(button); + expect(screen.getByText('Unable to create workspace')).toBeInTheDocument(); + expect(screen.queryByTestId('useCase.footer.modal.create.button')).not.toBeInTheDocument(); + fireEvent.click(getByTestId('useCase.footer.modal.close.button')); + }); + + it('renders open workspace button when one workspace exists', () => { + const core = getMockCore(); + core.workspaces.workspaceList$.next([ + { id: 'workspace-1', name: 'workspace 1', features: ['use-case-observability'] }, + ]); + const { getByTestId } = render( + + ); + + const button = getByTestId('useCase.footer.openWorkspace.button'); + expect(button).toBeInTheDocument(); + expect(button).not.toBeDisabled(); + expect(button).toHaveAttribute('href', 'https://test.com/w/workspace-1/app/discover'); + }); + + it('renders select workspace popover when multiple workspaces exist', () => { + const core = getMockCore(); + core.workspaces.workspaceList$.next([ + { id: 'workspace-1', name: 'workspace 1', features: ['use-case-observability'] }, + { id: 'workspace-2', name: 'workspace 2', features: ['use-case-observability'] }, + ]); + + const originalLocation = window.location; + Object.defineProperty(window, 'location', { + value: { + assign: jest.fn(), + }, + }); + + render( + + ); + + const button = screen.getByText('Select workspace'); + expect(button).toBeInTheDocument(); + + fireEvent.click(button); + expect(screen.getByText('workspace 1')).toBeInTheDocument(); + expect(screen.getByText('workspace 2')).toBeInTheDocument(); + expect(screen.getByText('Observability Workspaces')).toBeInTheDocument(); + + const inputElement = screen.getByPlaceholderText('Search'); + expect(inputElement).toBeInTheDocument(); + fireEvent.change(inputElement, { target: { value: 'workspace 1' } }); + expect(screen.queryByText('workspace 2')).toBeNull(); + + fireEvent.click(screen.getByText('workspace 1')); + expect(window.location.assign).toHaveBeenCalledWith( + 'https://test.com/w/workspace-1/app/discover' + ); + Object.defineProperty(window, 'location', { + value: originalLocation, + }); + }); +}); diff --git a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx new file mode 100644 index 000000000000..fddd542f64d7 --- /dev/null +++ b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx @@ -0,0 +1,219 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiText, + EuiModal, + EuiTitle, + EuiPanel, + EuiAvatar, + EuiSpacer, + EuiButton, + EuiPopover, + EuiFlexItem, + EuiModalBody, + EuiFlexGroup, + EuiFieldSearch, + EuiModalFooter, + EuiModalHeader, + EuiContextMenu, + EuiModalHeaderTitle, +} from '@elastic/eui'; +import React, { useMemo, useState } from 'react'; +import { FormattedMessage } from 'react-intl'; +import { i18n } from '@osd/i18n'; +import { BehaviorSubject } from 'rxjs'; +import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants'; +import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; +import { CoreStart, WorkspaceObject } from '../../../../../core/public'; +import { WorkspaceUseCase } from '../../types'; +import { getUseCaseFromFeatureConfig } from '../../utils'; + +export interface UseCaseFooterProps { + useCaseId: string; + useCaseTitle: string; + core: CoreStart; + registeredUseCases$: BehaviorSubject; +} + +export const UseCaseFooter = ({ + useCaseId, + useCaseTitle, + core, + registeredUseCases$, +}: UseCaseFooterProps) => { + const workspaceList = core.workspaces.workspaceList$.getValue(); + const availableUseCases = registeredUseCases$.getValue(); + const basePath = core.http.basePath; + const isDashboardAdmin = core.application.capabilities?.dashboards?.isDashboardAdmin !== false; + const [isPopoverOpen, setPopover] = useState(false); + const [searchValue, setSearchValue] = useState(''); + const [isModalVisible, setIsModalVisible] = useState(false); + const closeModal = () => setIsModalVisible(false); + const showModal = () => setIsModalVisible(!isModalVisible); + const onButtonClick = () => setPopover(!isPopoverOpen); + const closePopover = () => setPopover(false); + + const appId = + availableUseCases?.find((useCase) => useCase.id === useCaseId)?.features[0] ?? + WORKSPACE_DETAIL_APP_ID; + + const filterWorkspaces = useMemo( + () => + workspaceList.filter( + (workspace) => + workspace.features?.map(getUseCaseFromFeatureConfig).filter(Boolean)[0] === useCaseId + ), + [useCaseId, workspaceList] + ); + + const searchWorkspaces = useMemo( + () => + filterWorkspaces + .filter((workspace) => workspace.name.toLowerCase().includes(searchValue.toLowerCase())) + .slice(0, 5), + [filterWorkspaces, searchValue] + ); + + if (filterWorkspaces.length === 0) { + const modalHeaderTitle = i18n.translate('useCase.footer.modal.headerTitle', { + defaultMessage: isDashboardAdmin ? 'No workspaces found' : 'Unable to create workspace', + }); + const modalBodyContent = i18n.translate('useCase.footer.modal.bodyContent', { + defaultMessage: isDashboardAdmin + ? 'There are no available workspaces found. You can create a workspace in the workspace creation page.' + : 'To create a workspace, contact your administrator.', + }); + + return ( + <> + + + + {isModalVisible && ( + + + {modalHeaderTitle} + + + + {modalBodyContent} + + + + + + + {isDashboardAdmin && ( + + + + )} + + + )} + + ); + } + + if (filterWorkspaces.length === 1) { + const useCaseURL = formatUrlWithWorkspaceId( + core.application.getUrlForApp(appId, { absolute: false }), + filterWorkspaces[0].id, + basePath + ); + return ( + + + + ); + } + + const workspaceToItem = (workspace: WorkspaceObject) => { + const useCaseURL = formatUrlWithWorkspaceId( + core.application.getUrlForApp(appId, { absolute: false }), + workspace.id, + basePath + ); + const workspaceName = workspace.name; + + return { + toolTipContent:
{workspaceName}
, + name: ( + + {workspaceName} + + ), + key: workspace.id, + icon: ( + + ), + onClick: () => { + window.location.assign(useCaseURL); + }, + }; + }; + + const button = ( + + + + ); + const panels = [ + { + id: 0, + items: searchWorkspaces.map(workspaceToItem), + }, + ]; + + return ( + + + + + + + + +

{useCaseTitle} Workspaces

+
+
+
+ + setSearchValue(e.target.value)} + fullWidth + /> +
+ +
+ ); +}; diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx index d3578498c858..68ed1c67359f 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx @@ -109,18 +109,6 @@ describe('', () => { expect(screen.getByText('Observability')).toBeInTheDocument(); }); - it('should close the workspace dropdown list', async () => { - render(); - - fireEvent.click(screen.getByTestId('workspace-select-button')); - - expect(screen.getByText(/all workspaces/i)).toBeInTheDocument(); - fireEvent.click(screen.getByTestId('workspace-select-button')); - await waitFor(() => { - expect(screen.queryByText(/all workspaces/i)).not.toBeInTheDocument(); - }); - }); - it('should navigate to the workspace', () => { coreStartMock.workspaces.workspaceList$.next([ { id: 'workspace-1', name: 'workspace 1', features: ['use-case-observability'] }, diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx index bda11fb3d113..77d1cd6e602e 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx @@ -44,7 +44,7 @@ const allWorkspacesTitle = i18n.translate('workspace.menu.title.allWorkspaces', }); const recentWorkspacesTitle = i18n.translate('workspace.menu.title.recentWorkspaces', { - defaultMessage: 'recent workspaces', + defaultMessage: 'Recent workspaces', }); const createWorkspaceButton = i18n.translate('workspace.menu.button.createWorkspace', { @@ -158,6 +158,7 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { } onClick={() => { + closePopover(); window.location.assign(useCaseURL); }} /> @@ -221,6 +222,7 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { { + closePopover(); navigateToWorkspaceDetail(coreStart, currentWorkspace.id); }} > @@ -240,6 +242,7 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { { + closePopover(); coreStart.application.navigateToApp(WORKSPACE_LIST_APP_ID); }} > @@ -251,8 +254,9 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { - {getWorkspaceListGroup(filteredRecentWorkspaces, 'recent')} - {getWorkspaceListGroup(filteredWorkspaceList, 'all')} + {filteredRecentWorkspaces.length > 0 && + getWorkspaceListGroup(filteredRecentWorkspaces, 'recent')} + {filteredWorkspaceList.length > 0 && getWorkspaceListGroup(filteredWorkspaceList, 'all')} @@ -263,6 +267,7 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { key={WORKSPACE_LIST_APP_ID} data-test-subj="workspace-menu-view-all-button" onClick={() => { + closePopover(); coreStart.application.navigateToApp(WORKSPACE_LIST_APP_ID); }} > @@ -278,6 +283,7 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { key={WORKSPACE_CREATE_APP_ID} data-test-subj="workspace-menu-create-workspace-button" onClick={() => { + closePopover(); coreStart.application.navigateToApp(WORKSPACE_CREATE_APP_ID); }} > diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index fccd5745421f..8c33d1b77aa4 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -19,9 +19,13 @@ import { savedObjectsManagementPluginMock } from '../../saved_objects_management import { managementPluginMock } from '../../management/public/mocks'; import { UseCaseService } from './services/use_case_service'; import { workspaceClientMock, WorkspaceClientMock } from './workspace_client.mock'; -import { WorkspacePlugin } from './plugin'; +import { WorkspacePlugin, WorkspacePluginStartDeps } from './plugin'; +import { contentManagementPluginMocks } from '../../content_management/public'; describe('Workspace plugin', () => { + const mockDependencies: WorkspacePluginStartDeps = { + contentManagement: contentManagementPluginMocks.createStartContract(), + }; const getSetupMock = () => ({ ...coreMock.createSetup(), }); @@ -47,7 +51,7 @@ describe('Workspace plugin', () => { const setupMock = getSetupMock(); const coreStart = coreMock.createStart(); await workspacePlugin.setup(setupMock, {}); - workspacePlugin.start(coreStart); + workspacePlugin.start(coreStart, mockDependencies); coreStart.workspaces.currentWorkspaceId$.next('foo'); expect(coreStart.savedObjects.client.setCurrentWorkspace).toHaveBeenCalledWith('foo'); expect(setupMock.application.register).toBeCalledTimes(4); @@ -181,7 +185,7 @@ describe('Workspace plugin', () => { const breadcrumbs = new BehaviorSubject([{ text: 'dashboards' }]); startMock.chrome.getBreadcrumbs$.mockReturnValue(breadcrumbs); const workspacePlugin = new WorkspacePlugin(); - workspacePlugin.start(startMock); + workspacePlugin.start(startMock, mockDependencies); expect(startMock.chrome.setBreadcrumbs).toBeCalledWith( expect.arrayContaining([ expect.objectContaining({ @@ -207,7 +211,7 @@ describe('Workspace plugin', () => { ]); startMock.chrome.getBreadcrumbs$.mockReturnValue(breadcrumbs); const workspacePlugin = new WorkspacePlugin(); - workspacePlugin.start(startMock); + workspacePlugin.start(startMock, mockDependencies); expect(startMock.chrome.setBreadcrumbs).not.toHaveBeenCalled(); }); @@ -224,7 +228,7 @@ describe('Workspace plugin', () => { jest.spyOn(navGroupUpdater$, 'next'); expect(navGroupUpdater$.next).not.toHaveBeenCalled(); - workspacePlugin.start(coreStart); + workspacePlugin.start(coreStart, mockDependencies); waitFor(() => { expect(navGroupUpdater$.next).toHaveBeenCalled(); @@ -235,7 +239,7 @@ describe('Workspace plugin', () => { const coreStart = coreMock.createStart(); coreStart.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); const workspacePlugin = new WorkspacePlugin(); - workspacePlugin.start(coreStart); + workspacePlugin.start(coreStart, mockDependencies); expect(coreStart.chrome.navControls.registerLeftBottom).toBeCalledTimes(1); }); @@ -264,7 +268,7 @@ describe('Workspace plugin', () => { const appUpdater$ = setupMock.application.registerAppUpdater.mock.calls[0][0]; - workspacePlugin.start(coreStart); + workspacePlugin.start(coreStart, mockDependencies); const appUpdater = await appUpdater$.pipe(first()).toPromise(); @@ -285,7 +289,7 @@ describe('Workspace plugin', () => { const navGroupUpdater$ = setupMock.chrome.navGroup.registerNavGroupUpdater.mock.calls[0][0]; - workspacePlugin.start(coreStart); + workspacePlugin.start(coreStart, mockDependencies); const navGroupUpdater = await navGroupUpdater$.pipe(first()).toPromise(); @@ -336,7 +340,7 @@ describe('Workspace plugin', () => { const appUpdaterChangeMock = jest.fn(); appUpdater$.subscribe(appUpdaterChangeMock); - workspacePlugin.start(coreStart); + workspacePlugin.start(coreStart, mockDependencies); // Wait for filterNav been executed await new Promise(setImmediate); diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 104db7d9b91f..40f475d4a818 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -7,6 +7,7 @@ import { BehaviorSubject, combineLatest, Subscription } from 'rxjs'; import React from 'react'; import { i18n } from '@osd/i18n'; import { map } from 'rxjs/operators'; +import { EuiIcon } from '@elastic/eui'; import { Plugin, CoreStart, @@ -28,6 +29,7 @@ import { WORKSPACE_DETAIL_APP_ID, WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID, + WORKSPACE_USE_CASES, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; import { Services, WorkspaceUseCase } from './types'; @@ -46,6 +48,9 @@ import { import { recentWorkspaceManager } from './recent_workspace_manager'; import { toMountPoint } from '../../opensearch_dashboards_react/public'; import { UseCaseService } from './services/use_case_service'; +import { ContentManagementPluginStart } from '../../../plugins/content_management/public'; +import { UseCaseFooter } from './components/home_get_start_card'; +import { HOME_CONTENT_AREAS } from '../../home/public'; type WorkspaceAppType = ( params: AppMountParameters, @@ -59,7 +64,12 @@ interface WorkspacePluginSetupDeps { dataSourceManagement?: DataSourceManagementPluginSetup; } -export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> { +export interface WorkspacePluginStartDeps { + contentManagement: ContentManagementPluginStart; +} + +export class WorkspacePlugin + implements Plugin<{}, {}, WorkspacePluginSetupDeps, WorkspacePluginStartDeps> { private coreStart?: CoreStart; private currentWorkspaceSubscription?: Subscription; private breadcrumbsSubscription?: Subscription; @@ -372,7 +382,41 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> return {}; } - public start(core: CoreStart) { + private registerGetStartedCardToNewHome( + core: CoreStart, + contentManagement: ContentManagementPluginStart + ) { + const useCases = [ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.search, + WORKSPACE_USE_CASES.analytics, + ]; + + useCases.forEach((useCase, index) => { + contentManagement.registerContentProvider({ + id: `home_get_start_${useCase.id}`, + getTargetArea: () => HOME_CONTENT_AREAS.GET_STARTED, + getContent: () => ({ + id: useCase.id, + kind: 'card', + order: (index + 1) * 1000, + description: useCase.description, + title: useCase.title, + getIcon: () => React.createElement(EuiIcon, { size: 'xl', type: 'logoOpenSearch' }), + getFooter: () => + React.createElement(UseCaseFooter, { + useCaseId: useCase.id, + useCaseTitle: useCase.title, + core, + registeredUseCases$: this.registeredUseCases$, + }), + }), + }); + }); + } + + public start(core: CoreStart, { contentManagement }: WorkspacePluginStartDeps) { this.coreStart = core; this.currentWorkspaceIdSubscription = this._changeSavedObjectCurrentWorkspace(); @@ -405,8 +449,10 @@ export class WorkspacePlugin implements Plugin<{}, {}, WorkspacePluginSetupDeps> }) ), }); - } + // register get started card in new home page + this.registerGetStartedCardToNewHome(core, contentManagement); + } return {}; } From c30287abcfdc3cf0d8dc05773abd08d6d6e8bc9f Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 17:03:18 -0700 Subject: [PATCH 094/276] fix: Fix wrapping of labels in filter by type popover (#7327) (#7345) * fix: Fix wrapping of labels in filter by type popover --------- (cherry picked from commit 376ead0ce1ef5224476604e48aa487354fbb0387) Signed-off-by: Viraj Sanghvi Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7327.yml | 2 ++ .../data_explorer/public/components/sidebar/index.scss | 4 ++++ .../application/components/sidebar/discover_field_search.tsx | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/7327.yml diff --git a/changelogs/fragments/7327.yml b/changelogs/fragments/7327.yml new file mode 100644 index 000000000000..da4ffa480766 --- /dev/null +++ b/changelogs/fragments/7327.yml @@ -0,0 +1,2 @@ +fix: +- Fix wrapping of labels in filter by type popover ([#7327](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7327)) \ No newline at end of file diff --git a/src/plugins/data_explorer/public/components/sidebar/index.scss b/src/plugins/data_explorer/public/components/sidebar/index.scss index 6d8ad2324bc1..1828568bc361 100644 --- a/src/plugins/data_explorer/public/components/sidebar/index.scss +++ b/src/plugins/data_explorer/public/components/sidebar/index.scss @@ -7,3 +7,7 @@ border-bottom: $euiBorderThin !important; } } + +.dataPanelTypeFilterPopover { + min-width: 300px; +} diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_search.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field_search.tsx index 4b50c44b3235..ec4bc5f2896d 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field_search.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_search.tsx @@ -258,7 +258,7 @@ export function DiscoverFieldSearch({ onChange, value, types }: Props) { Date: Mon, 22 Jul 2024 14:41:57 +0800 Subject: [PATCH 095/276] [navigation-next] fix: redirect to standard index pattern applications while nav group is enabled (#7346) (#7352) * [navigation-next] fix: redirect to standard index pattern applications while nav group is enabled (#7305) * feat: fix the incorrect jumping logic for Index pattern management * Changeset file for PR #7305 created/updated * feat: update * feat: update with comment * feat: update order and remove reset logic * feat: update * feat: update * feat: update snapshot * feat: some category change * feat: update category --------- (cherry picked from commit 2c708e320222f7eee43e96247a71529e3f0207b4) * feat: change the order * feat: hide left navigation when workspace enabled --------- (cherry picked from commit d30677d72b58ad0c52fc553630ef1553de7313f9) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: SuZhou-Joe --- changelogs/fragments/7305.yml | 2 + .../nav_group/nav_group_service.test.ts | 47 ----------- .../chrome/nav_group/nav_group_service.ts | 12 --- ...ollapsible_nav_group_enabled.test.tsx.snap | 7 +- .../header/collapsible_nav_group_enabled.scss | 17 +++- .../collapsible_nav_group_enabled.test.tsx | 26 ++++++ .../header/collapsible_nav_group_enabled.tsx | 80 ++++++++++++------- src/core/public/chrome/ui/header/header.tsx | 1 + src/core/utils/default_app_categories.ts | 9 ++- src/plugins/dashboard/public/plugin.tsx | 4 +- .../data_source_management/public/plugin.ts | 15 ++-- .../public/plugin.test.ts | 36 +++++++++ .../index_pattern_management/public/plugin.ts | 20 +++-- .../management_app/management_app.tsx | 5 +- src/plugins/management/public/plugin.ts | 2 + .../saved_objects_management/public/plugin.ts | 8 ++ 16 files changed, 182 insertions(+), 109 deletions(-) create mode 100644 changelogs/fragments/7305.yml diff --git a/changelogs/fragments/7305.yml b/changelogs/fragments/7305.yml new file mode 100644 index 000000000000..ebb9060e2121 --- /dev/null +++ b/changelogs/fragments/7305.yml @@ -0,0 +1,2 @@ +feat: +- [navigation-next] fix: redirect to standard index pattern applications while nav group is enabled ([#7305](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7305)) \ No newline at end of file diff --git a/src/core/public/chrome/nav_group/nav_group_service.test.ts b/src/core/public/chrome/nav_group/nav_group_service.test.ts index bc18483178fd..90911309ff9a 100644 --- a/src/core/public/chrome/nav_group/nav_group_service.test.ts +++ b/src/core/public/chrome/nav_group/nav_group_service.test.ts @@ -311,53 +311,6 @@ describe('ChromeNavGroupService#start()', () => { expect(sessionStorageMock.getItem(CURRENT_NAV_GROUP_ID)).toBeFalsy(); expect(currentNavGroup).toBeUndefined(); }); - - it('should reset current nav group if app not belongs to any nav group', async () => { - const uiSettings = uiSettingsServiceMock.createSetupContract(); - const navGroupEnabled$ = new Rx.BehaviorSubject(true); - uiSettings.get$.mockImplementation(() => navGroupEnabled$); - - const chromeNavGroupService = new ChromeNavGroupService(); - const chromeNavGroupServiceSetup = chromeNavGroupService.setup({ uiSettings }); - - chromeNavGroupServiceSetup.addNavLinksToGroup( - { - id: 'foo', - title: 'foo title', - description: 'foo description', - }, - [{ id: 'foo-app1' }] - ); - - const chromeNavGroupServiceStart = await chromeNavGroupService.start({ - navLinks: mockedNavLinkService, - application: mockedApplicationService, - }); - - // set an existing nav group id - chromeNavGroupServiceStart.setCurrentNavGroup('foo'); - - expect(sessionStorageMock.getItem(CURRENT_NAV_GROUP_ID)).toEqual('foo'); - - let currentNavGroup = await chromeNavGroupServiceStart - .getCurrentNavGroup$() - .pipe(first()) - .toPromise(); - - expect(currentNavGroup?.id).toEqual('foo'); - - // navigate to app don't belongs to any nav group - mockedApplicationService.navigateToApp('bar-app'); - - currentNavGroup = await chromeNavGroupServiceStart - .getCurrentNavGroup$() - .pipe(first()) - .toPromise(); - - // verify current nav group been reset - expect(currentNavGroup).toBeFalsy(); - expect(sessionStorageMock.getItem(CURRENT_NAV_GROUP_ID)).toBeFalsy(); - }); }); describe('nav group updater', () => { diff --git a/src/core/public/chrome/nav_group/nav_group_service.ts b/src/core/public/chrome/nav_group/nav_group_service.ts index bde7d0d9111a..bdf69b151da9 100644 --- a/src/core/public/chrome/nav_group/nav_group_service.ts +++ b/src/core/public/chrome/nav_group/nav_group_service.ts @@ -212,18 +212,6 @@ export class ChromeNavGroupService { } }; - // erase current nav group when switch app don't belongs to any nav group - application.currentAppId$.subscribe((appId) => { - const navGroupMap = this.navGroupsMap$.getValue(); - const appIdsWithNavGroup = Object.values(navGroupMap).flatMap(({ navLinks: links }) => - links.map(({ id }) => id) - ); - - if (appId && !appIdsWithNavGroup.includes(appId)) { - setCurrentNavGroup(undefined); - } - }); - const currentNavGroupSorted$ = combineLatest([ this.getSortedNavGroupsMap$(), this.currentNavGroup$, diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap index 61fb739ad6c2..56600b067583 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap @@ -1,5 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[` should hide left navigation when in home page when workspace is enabled 1`] = `
`; + exports[` should render correctly 1`] = `
should render correctly 1`] = ` />
@@ -266,8 +267,7 @@ exports[` should render correctly 2`] = ` class="euiHorizontalRule euiHorizontalRule--full" />
@@ -341,7 +341,6 @@ exports[` should show all use case by default and />
diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss index 50e822bae295..77626cab7eb7 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss @@ -2,8 +2,8 @@ border: none !important; .nav-link-item { - padding: $ouiSize / 4 $ouiSize; - border-radius: $ouiSize; + padding: calc($euiSize / 4) $euiSize; + border-radius: $euiSize; box-shadow: none; margin-bottom: 0; margin-top: 0; @@ -39,11 +39,20 @@ } .bottom-container { - padding: 0 $ouiSize; + padding: 0 $euiSize; display: flex; + + &.bottom-container-collapsed { + flex-direction: column; + align-items: center; + + > * { + margin: $euiSizeS 0; + } + } } .nav-controls-padding { - padding: $ouiSize; + padding: $euiSize; } } diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx index b08029553b50..fa4abffac36c 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx @@ -18,6 +18,7 @@ import { httpServiceMock } from '../../../mocks'; import { getLogos } from '../../../../common'; import { ALL_USE_CASE_ID, DEFAULT_NAV_GROUPS } from '../../../../public'; import { CollapsibleNavTopProps } from './collapsible_nav_group_enabled_top'; +import { capabilitiesServiceMock } from '../../../application/capabilities/capabilities_service.mock'; jest.mock('./collapsible_nav_group_enabled_top', () => ({ CollapsibleNavTop: (props: CollapsibleNavTopProps) => ( @@ -166,6 +167,7 @@ describe('', () => { currentNavGroup$.next(undefined); } }, + capabilities: { ...capabilitiesServiceMock.createStartContract().capabilities }, ...props, }; } @@ -223,4 +225,28 @@ describe('', () => { fireEvent.click(getByTestId('back')); expect(getAllByTestId('collapsibleNavAppLink-link-in-analytics').length).toEqual(2); }); + + it('should hide left navigation when in home page when workspace is enabled', async () => { + const props = mockProps({ + navGroupsMap: { + [DEFAULT_NAV_GROUPS.analytics.id]: { + ...DEFAULT_NAV_GROUPS.analytics, + navLinks: [ + { + id: 'link-in-analytics', + title: 'link-in-analytics', + showInAllNavGroup: true, + }, + ], + }, + }, + }); + props.appId$ = new BehaviorSubject('home'); + if (props.capabilities.workspaces) { + (props.capabilities.workspaces as Record) = {}; + (props.capabilities.workspaces as Record).enabled = true; + } + const { container } = render(); + expect(container).toMatchSnapshot(); + }); }); diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx index 0575dc997fc7..68b031232370 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx @@ -19,7 +19,7 @@ import useObservable from 'react-use/lib/useObservable'; import * as Rx from 'rxjs'; import classNames from 'classnames'; import { ChromeNavControl, ChromeNavLink } from '../..'; -import { NavGroupStatus } from '../../../../types'; +import { AppCategory, NavGroupStatus } from '../../../../types'; import { InternalApplicationStart } from '../../../application/types'; import { HttpStart } from '../../../http'; import { OnIsLockedUpdate } from './'; @@ -36,7 +36,7 @@ import { LinkItem, LinkItemType, } from '../../utils'; -import { ALL_USE_CASE_ID } from '../../../../../core/utils'; +import { ALL_USE_CASE_ID, DEFAULT_APP_CATEGORIES } from '../../../../../core/utils'; import { CollapsibleNavTop } from './collapsible_nav_group_enabled_top'; import { HeaderNavControls } from './header_nav_controls'; @@ -58,6 +58,7 @@ export interface CollapsibleNavGroupEnabledProps { navControlsLeftBottom$: Rx.Observable; currentNavGroup$: Rx.Observable; setCurrentNavGroup: ChromeNavGroupServiceStartContract['setCurrentNavGroup']; + capabilities: InternalApplicationStart['capabilities']; } interface NavGroupsProps { @@ -164,6 +165,14 @@ export function NavGroups({ ); } +// Custom category is used for those features not belong to any of use cases in all use case. +// and the custom category should always sit before manage category +const customCategory: AppCategory = { + id: 'custom', + label: i18n.translate('core.ui.customNavList.label', { defaultMessage: 'Custom' }), + order: (DEFAULT_APP_CATEGORIES.manage.order || 0) - 500, +}; + export function CollapsibleNavGroupEnabled({ basePath, id, @@ -176,6 +185,7 @@ export function CollapsibleNavGroupEnabled({ navigateToUrl, logos, setCurrentNavGroup, + capabilities, ...observables }: CollapsibleNavGroupEnabledProps) { const navLinks = useObservable(observables.navLinks$, []).filter((link) => !link.hidden); @@ -183,29 +193,6 @@ export function CollapsibleNavGroupEnabled({ const navGroupsMap = useObservable(observables.navGroupsMap$, {}); const currentNavGroup = useObservable(observables.currentNavGroup$, undefined); - const onGroupClick = ( - e: React.MouseEvent, - group: NavGroupItemInMap - ) => { - const fulfilledLinks = fulfillRegistrationLinksToChromeNavLinks( - navGroupsMap[group.id]?.navLinks, - navLinks - ); - setCurrentNavGroup(group.id); - - // the `navGroupsMap[group.id]?.navLinks` has already been sorted - const firstLink = fulfilledLinks[0]; - if (firstLink) { - const propsForEui = createEuiListItem({ - link: firstLink, - appId, - dataTestSubj: 'collapsibleNavAppLink', - navigateToApp, - }); - propsForEui.onClick(e); - } - }; - const navLinksForRender: ChromeNavLink[] = useMemo(() => { if (currentNavGroup) { return fulfillRegistrationLinksToChromeNavLinks( @@ -234,7 +221,10 @@ export function CollapsibleNavGroupEnabled({ navLinks .filter((link) => !linkIdsWithUseGroupInfo.includes(link.id)) .forEach((navLink) => { - navLinksForAll.push(navLink); + navLinksForAll.push({ + ...navLink, + category: customCategory, + }); }); // Append all the links registered to all use case @@ -281,6 +271,37 @@ export function CollapsibleNavGroupEnabled({ return 270; }, [isNavOpen]); + // For now, only home page need to hide left navigation + // when workspace is enabled. + // If there are more pages need to hide left navigation in the future + // need to come up with a mechanism to register. + if (capabilities.workspaces.enabled && appId === 'home') { + return null; + } + + const onGroupClick = ( + e: React.MouseEvent, + group: NavGroupItemInMap + ) => { + const fulfilledLinks = fulfillRegistrationLinksToChromeNavLinks( + navGroupsMap[group.id]?.navLinks, + navLinks + ); + setCurrentNavGroup(group.id); + + // the `navGroupsMap[group.id]?.navLinks` has already been sorted + const firstLink = fulfilledLinks[0]; + if (firstLink) { + const propsForEui = createEuiListItem({ + link: firstLink, + appId, + dataTestSubj: 'collapsibleNavAppLink', + navigateToApp, + }); + propsForEui.onClick(e); + } + }; + return (
-
+
) : ( = Object.freeze label: i18n.translate('core.ui.manageNav.label', { defaultMessage: 'Manage', }), - order: 7000, + order: 8000, + }, + manageData: { + id: 'manageData', + label: i18n.translate('core.ui.manageDataNav.label', { + defaultMessage: 'Manage data', + }), + order: 1000, }, }); diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index afa3b6daf281..bbe000f12b79 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -456,14 +456,14 @@ export class DashboardPlugin core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ { id: app.id, - order: 300, + order: 400, category: undefined, }, ]); core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ { id: app.id, - order: 300, + order: 400, category: undefined, }, ]); diff --git a/src/plugins/data_source_management/public/plugin.ts b/src/plugins/data_source_management/public/plugin.ts index d2f4ac55c889..19154f6a3a00 100644 --- a/src/plugins/data_source_management/public/plugin.ts +++ b/src/plugins/data_source_management/public/plugin.ts @@ -133,11 +133,8 @@ export class DataSourceManagementPlugin core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.dataAdministration, [ { id: DSM_APP_ID_FOR_STANDARD_APPLICATION, - category: { - id: DSM_APP_ID_FOR_STANDARD_APPLICATION, - label: PLUGIN_NAME, - order: 200, - }, + category: DEFAULT_APP_CATEGORIES.manageData, + order: 100, }, ]); @@ -173,6 +170,14 @@ export class DataSourceManagementPlugin }, ]); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ + { + id: DSM_APP_ID_FOR_STANDARD_APPLICATION, + category: DEFAULT_APP_CATEGORIES.manage, + order: 100, + }, + ]); + const registerAuthenticationMethod = (authMethod: AuthenticationMethod) => { if (this.started) { throw new Error( diff --git a/src/plugins/index_pattern_management/public/plugin.test.ts b/src/plugins/index_pattern_management/public/plugin.test.ts index e207af770af3..a0525acae2dc 100644 --- a/src/plugins/index_pattern_management/public/plugin.test.ts +++ b/src/plugins/index_pattern_management/public/plugin.test.ts @@ -7,6 +7,11 @@ import { coreMock } from '../../../core/public/mocks'; import { IndexPatternManagementPlugin } from './plugin'; import { urlForwardingPluginMock } from '../../url_forwarding/public/mocks'; import { managementPluginMock } from '../../management/public/mocks'; +import { + ManagementApp, + ManagementAppMountParams, + RegisterManagementAppArgs, +} from 'src/plugins/management/public'; describe('DiscoverPlugin', () => { it('setup successfully', () => { @@ -22,4 +27,35 @@ describe('DiscoverPlugin', () => { expect(setupMock.application.register).toBeCalledTimes(1); expect(setupMock.chrome.navGroup.addNavLinksToGroup).toBeCalledTimes(5); }); + + it('when new navigation is enabled, should navigate to standard IPM app', async () => { + const setupMock = coreMock.createSetup(); + const startMock = coreMock.createStart(); + setupMock.getStartServices.mockResolvedValue([startMock, {}, {}]); + const initializerContext = coreMock.createPluginInitializerContext(); + const pluginInstance = new IndexPatternManagementPlugin(initializerContext); + const managementMock = managementPluginMock.createSetupContract(); + let applicationRegistration = {} as Omit; + managementMock.sections.section.opensearchDashboards.registerApp = ( + app: Omit + ) => { + applicationRegistration = app; + return {} as ManagementApp; + }; + + setupMock.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); + startMock.application.getUrlForApp.mockReturnValue('/app/indexPatterns'); + + pluginInstance.setup(setupMock, { + urlForwarding: urlForwardingPluginMock.createSetupContract(), + management: managementMock, + }); + + await applicationRegistration.mount({} as ManagementAppMountParams); + + expect(startMock.application.getUrlForApp).toBeCalledWith('indexPatterns'); + expect(startMock.application.navigateToUrl).toBeCalledWith( + 'http://localhost/app/indexPatterns' + ); + }); }); diff --git a/src/plugins/index_pattern_management/public/plugin.ts b/src/plugins/index_pattern_management/public/plugin.ts index 7ee82dbcc3b0..ef462374129e 100644 --- a/src/plugins/index_pattern_management/public/plugin.ts +++ b/src/plugins/index_pattern_management/public/plugin.ts @@ -111,6 +111,17 @@ export class IndexPatternManagementPlugin title: sectionsHeader, order: 0, mount: async (params) => { + if (core.chrome.navGroup.getNavGroupEnabled()) { + const [coreStart] = await core.getStartServices(); + const urlForStandardIPMApp = new URL( + coreStart.application.getUrlForApp(IPM_APP_ID), + window.location.href + ); + const targetUrl = new URL(window.location.href); + targetUrl.pathname = urlForStandardIPMApp.pathname; + coreStart.application.navigateToUrl(targetUrl.toString()); + return () => {}; + } const { mountManagementSection } = await import('./management_app'); return mountManagementSection( @@ -178,14 +189,11 @@ export class IndexPatternManagementPlugin }, ]); - core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.dataAdministration, [ + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ { id: IPM_APP_ID, - category: { - id: IPM_APP_ID, - label: sectionsHeader, - order: 100, - }, + category: DEFAULT_APP_CATEGORIES.manage, + order: 200, }, ]); diff --git a/src/plugins/management/public/components/management_app/management_app.tsx b/src/plugins/management/public/components/management_app/management_app.tsx index b2109ceb08ca..c30243563b01 100644 --- a/src/plugins/management/public/components/management_app/management_app.tsx +++ b/src/plugins/management/public/components/management_app/management_app.tsx @@ -51,6 +51,7 @@ export interface ManagementAppDependencies { sections: SectionsServiceStart; opensearchDashboardsVersion: string; setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; + hideInAppNavigation?: boolean; } export const ManagementApp = ({ dependencies, history }: ManagementAppProps) => { @@ -89,7 +90,9 @@ export const ManagementApp = ({ dependencies, history }: ManagementAppProps) => return ( - + {dependencies.hideInAppNavigation ? null : ( + + )} Date: Mon, 22 Jul 2024 14:48:14 +0800 Subject: [PATCH 096/276] [Navigation-next]Register workspace list card into home page (#7247) (#7350) * workspace list card on home * fix merge conflicts * add home as requiredBundles * Changeset file for PR #7247 created/updated * fix failed UT * address review comments * update to funtional component * udpate content provider id --------- (cherry picked from commit b32eade57c5abadf87ca1f7ffeeeb0c95f42b183) Signed-off-by: Hailong Cui Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7247.yml | 2 + src/core/types/workspace.ts | 1 + .../workspace_list_card.test.tsx.snap | 121 +++++++++++ .../public/components/service_card/index.ts | 6 + .../service_card/workspace_list_card.test.tsx | 66 ++++++ .../service_card/workspace_list_card.tsx | 192 ++++++++++++++++++ src/plugins/workspace/public/plugin.test.ts | 13 ++ src/plugins/workspace/public/plugin.ts | 24 ++- src/plugins/workspace/public/utils.ts | 2 +- .../workspace/server/workspace_client.ts | 1 + 10 files changed, 426 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/7247.yml create mode 100644 src/plugins/workspace/public/components/service_card/__snapshots__/workspace_list_card.test.tsx.snap create mode 100644 src/plugins/workspace/public/components/service_card/index.ts create mode 100644 src/plugins/workspace/public/components/service_card/workspace_list_card.test.tsx create mode 100644 src/plugins/workspace/public/components/service_card/workspace_list_card.tsx diff --git a/changelogs/fragments/7247.yml b/changelogs/fragments/7247.yml new file mode 100644 index 000000000000..535f4c9843b0 --- /dev/null +++ b/changelogs/fragments/7247.yml @@ -0,0 +1,2 @@ +feat: +- Register workspace list card into home page ([#7247](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7247)) \ No newline at end of file diff --git a/src/core/types/workspace.ts b/src/core/types/workspace.ts index d0a0d47b2216..c00d3576d567 100644 --- a/src/core/types/workspace.ts +++ b/src/core/types/workspace.ts @@ -14,6 +14,7 @@ export interface WorkspaceAttribute { icon?: string; reserved?: boolean; uiSettings?: Record; + lastUpdatedTime?: string; } export interface WorkspaceAttributeWithPermission extends WorkspaceAttribute { diff --git a/src/plugins/workspace/public/components/service_card/__snapshots__/workspace_list_card.test.tsx.snap b/src/plugins/workspace/public/components/service_card/__snapshots__/workspace_list_card.test.tsx.snap new file mode 100644 index 000000000000..35970676eb7e --- /dev/null +++ b/src/plugins/workspace/public/components/service_card/__snapshots__/workspace_list_card.test.tsx.snap @@ -0,0 +1,121 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`workspace list card render normally should show workspace list card correctly 1`] = ` +
+
+
+
+

+ Workspaces +

+
+
+ + + +
+
+
+
+ +
+ + +
+
+
+
+
+
+
    +
    + +
    +

    + No Workspaces found +

    + +
    +
    + Workspaces you have recently viewed will appear here. +
    + +
    +
+ +
+
+`; diff --git a/src/plugins/workspace/public/components/service_card/index.ts b/src/plugins/workspace/public/components/service_card/index.ts new file mode 100644 index 000000000000..9bfc561f2561 --- /dev/null +++ b/src/plugins/workspace/public/components/service_card/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { WorkspaceListCard } from './workspace_list_card'; diff --git a/src/plugins/workspace/public/components/service_card/workspace_list_card.test.tsx b/src/plugins/workspace/public/components/service_card/workspace_list_card.test.tsx new file mode 100644 index 000000000000..24d45d42e725 --- /dev/null +++ b/src/plugins/workspace/public/components/service_card/workspace_list_card.test.tsx @@ -0,0 +1,66 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { coreMock } from '../../../../../core/public/mocks'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { WorkspaceListCard } from './workspace_list_card'; +import { recentWorkspaceManager } from '../../recent_workspace_manager'; + +describe('workspace list card render normally', () => { + const coreStart = coreMock.createStart(); + + beforeAll(() => { + const workspaceList = [ + { + id: 'ws-1', + name: 'foo', + lastUpdatedTime: new Date().toISOString(), + }, + { + id: 'ws-2', + name: 'bar', + lastUpdatedTime: new Date().toISOString(), + }, + ]; + coreStart.workspaces.workspaceList$.next(workspaceList); + }); + + it('should show workspace list card correctly', () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('should show empty state if no recently viewed workspace', () => { + const { getByTestId, getByText } = render(); + expect(getByTestId('workspace_filter')).toHaveDisplayValue('Recently viewed'); + + // empty statue for recently viewed + expect(getByText('Workspaces you have recently viewed will appear here.')).toBeInTheDocument(); + }); + + it('should show default filter as recently viewed', () => { + recentWorkspaceManager.addRecentWorkspace('foo'); + const { getByTestId, getByText } = render(); + expect(getByTestId('workspace_filter')).toHaveDisplayValue('Recently viewed'); + + waitFor(() => { + expect(getByText('foo')).toBeInTheDocument(); + }); + }); + + it('should show updated filter correctly', () => { + const { getByTestId, getByText } = render(); + expect(getByTestId('workspace_filter')).toHaveDisplayValue('Recently viewed'); + + const filterSelector = getByTestId('workspace_filter'); + fireEvent.change(filterSelector, { target: { value: 'updated' } }); + expect(getByTestId('workspace_filter')).toHaveDisplayValue('Recently updated'); + + // workspace list + expect(getByText('foo')).toBeInTheDocument(); + expect(getByText('bar')).toBeInTheDocument(); + }); +}); diff --git a/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx b/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx new file mode 100644 index 000000000000..12b14325ce11 --- /dev/null +++ b/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx @@ -0,0 +1,192 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState, useEffect, useMemo } from 'react'; +import { + EuiPanel, + EuiLink, + EuiDescriptionList, + EuiIcon, + EuiFlexGroup, + EuiFlexItem, + EuiSelect, + EuiButtonIcon, + EuiSpacer, + EuiListGroup, + EuiText, + EuiTitle, + EuiToolTip, + EuiEmptyPrompt, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import moment from 'moment'; +import { orderBy } from 'lodash'; +import { CoreStart, WorkspaceObject } from '../../../../../core/public'; +import { navigateToWorkspaceDetail } from '../utils/workspace'; + +import { WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID } from '../../../common/constants'; +import { recentWorkspaceManager } from '../../recent_workspace_manager'; + +const WORKSPACE_LIST_CARD_DESCRIPTION = i18n.translate('workspace.list.card.description', { + defaultMessage: + 'Workspaces are dedicated environments for organizing and collaborating on your data, dashboards, and analytics workflows. Each Workspace acts as a self-contained space with its own set of saved objects and access controls.', +}); + +const MAX_ITEM_IN_LIST = 5; + +export interface WorkspaceListCardProps { + core: CoreStart; +} + +export const WorkspaceListCard = (props: WorkspaceListCardProps) => { + const [availableWorkspaces, setAvailableWorkspaces] = useState([]); + const [filter, setFilter] = useState('viewed'); + + useEffect(() => { + const workspaceSub = props.core.workspaces.workspaceList$.subscribe((list) => { + setAvailableWorkspaces(list || []); + }); + return () => { + workspaceSub.unsubscribe(); + }; + }, [props.core]); + + const workspaceList = useMemo(() => { + const recentWorkspaces = recentWorkspaceManager.getRecentWorkspaces() || []; + if (filter === 'viewed') { + return orderBy(recentWorkspaces, ['timestamp'], ['desc']) + .filter((ws) => availableWorkspaces.some((a) => a.id === ws.id)) + .slice(0, MAX_ITEM_IN_LIST) + .map((item) => ({ + id: item.id, + name: availableWorkspaces.find((ws) => ws.id === item.id)?.name!, + time: item.timestamp, + })); + } else if (filter === 'updated') { + return orderBy(availableWorkspaces, ['lastUpdatedTime'], ['desc']) + .slice(0, MAX_ITEM_IN_LIST) + .map((ws) => ({ + id: ws.id, + name: ws.name, + time: ws.lastUpdatedTime, + })); + } + return []; + }, [filter, availableWorkspaces]); + + const handleSwitchWorkspace = (id: string) => { + const { application, http } = props.core; + if (application && http) { + navigateToWorkspaceDetail({ application, http }, id); + } + }; + + const { application } = props.core; + + const isDashboardAdmin = application.capabilities.dashboards?.isDashboardAdmin; + + return ( + + + + +

Workspaces

+
+
+ + + + + + + { + setFilter(e.target.value); + }} + options={[ + { + value: 'viewed', + text: i18n.translate('workspace.list.card.filter.viewed', { + defaultMessage: 'Recently viewed', + }), + }, + { + value: 'updated', + text: i18n.translate('workspace.list.card.filter.updated', { + defaultMessage: 'Recently updated', + }), + }, + ]} + /> + + {isDashboardAdmin && ( + + + { + application.navigateToApp(WORKSPACE_CREATE_APP_ID); + }} + /> + + + )} +
+ + + + {workspaceList && workspaceList.length === 0 ? ( + No Workspaces found

} + body={i18n.translate('workspace.list.card.empty', { + values: { + filter, + }, + defaultMessage: 'Workspaces you have recently {filter} will appear here.', + })} + /> + ) : ( + ({ + title: ( + { + handleSwitchWorkspace(workspace.id); + }} + > + {workspace.name} + + ), + description: ( + + {moment(workspace.time).fromNow()} + + ), + }))} + /> + )} +
+ + { + application.navigateToApp(WORKSPACE_LIST_APP_ID); + }} + > + View all + +
+ ); +}; diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 8c33d1b77aa4..ef41ed233158 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -29,6 +29,7 @@ describe('Workspace plugin', () => { const getSetupMock = () => ({ ...coreMock.createSetup(), }); + beforeEach(() => { WorkspaceClientMock.mockClear(); Object.values(workspaceClientMock).forEach((item) => item.mockClear()); @@ -215,6 +216,18 @@ describe('Workspace plugin', () => { expect(startMock.chrome.setBreadcrumbs).not.toHaveBeenCalled(); }); + it('#start should register workspace list card into new home page', async () => { + const startMock = coreMock.createStart(); + startMock.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); + const workspacePlugin = new WorkspacePlugin(); + workspacePlugin.start(startMock, mockDependencies); + expect(mockDependencies.contentManagement.registerContentProvider).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'workspace_list_card_home', + }) + ); + }); + it('#start should call navGroupUpdater$.next after currentWorkspace set', async () => { const workspacePlugin = new WorkspacePlugin(); const setupMock = getSetupMock(); diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 40f475d4a818..1be221b546ad 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -36,6 +36,7 @@ import { Services, WorkspaceUseCase } from './types'; import { WorkspaceClient } from './workspace_client'; import { SavedObjectsManagementPluginSetup } from '../../../plugins/saved_objects_management/public'; import { ManagementSetup } from '../../../plugins/management/public'; +import { ContentManagementPluginStart } from '../../../plugins/content_management/public'; import { WorkspaceMenu } from './components/workspace_menu/workspace_menu'; import { getWorkspaceColumn } from './components/workspace_column'; import { DataSourceManagementPluginSetup } from '../../../plugins/data_source_management/public'; @@ -48,7 +49,7 @@ import { import { recentWorkspaceManager } from './recent_workspace_manager'; import { toMountPoint } from '../../opensearch_dashboards_react/public'; import { UseCaseService } from './services/use_case_service'; -import { ContentManagementPluginStart } from '../../../plugins/content_management/public'; +import { WorkspaceListCard } from './components/service_card'; import { UseCaseFooter } from './components/home_get_start_card'; import { HOME_CONTENT_AREAS } from '../../home/public'; @@ -450,12 +451,33 @@ export class WorkspacePlugin ), }); + // register workspace list in home page + this.registerWorkspaceListToHome(core, contentManagement); + // register get started card in new home page this.registerGetStartedCardToNewHome(core, contentManagement); } return {}; } + private registerWorkspaceListToHome( + core: CoreStart, + contentManagement: ContentManagementPluginStart + ) { + if (contentManagement) { + contentManagement.registerContentProvider({ + id: 'workspace_list_card_home', + getContent: () => ({ + id: 'workspace_list', + kind: 'custom', + order: 0, + render: () => React.createElement(WorkspaceListCard, { core }), + }), + getTargetArea: () => HOME_CONTENT_AREAS.SERVICE_CARDS, + }); + } + } + public stop() { this.currentWorkspaceSubscription?.unsubscribe(); this.currentWorkspaceIdSubscription?.unsubscribe(); diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index 589f1d8159d2..d4bc61638744 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -18,8 +18,8 @@ import { WorkspaceObject, WorkspaceAvailability, } from '../../../core/public'; -import { DEFAULT_SELECTED_FEATURES_IDS } from '../common/constants'; import { WorkspaceUseCase } from './types'; +import { DEFAULT_SELECTED_FEATURES_IDS } from '../common/constants'; const USE_CASE_PREFIX = 'use-case-'; diff --git a/src/plugins/workspace/server/workspace_client.ts b/src/plugins/workspace/server/workspace_client.ts index fe88436f38e5..0b7d7c8a57c1 100644 --- a/src/plugins/workspace/server/workspace_client.ts +++ b/src/plugins/workspace/server/workspace_client.ts @@ -77,6 +77,7 @@ export class WorkspaceClient implements IWorkspaceClientImpl { ): WorkspaceAttributeWithPermission { return { ...savedObject.attributes, + lastUpdatedTime: savedObject.updated_at, id: savedObject.id, permissions: savedObject.permissions, }; From d59e3ea639c08f269cc29d8aa4992b126ef262c6 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:02:04 +0800 Subject: [PATCH 097/276] fix: data source selector in dev tools tab moved to left (#7347) (#7353) * fix: style issue that data source selector in dev tools tab moved to left * Changeset file for PR #7347 created/updated --------- (cherry picked from commit 9ce538a1c9638973aa073ed9770a16490528ca53) Signed-off-by: Yulong Ruan Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7347.yml | 2 ++ src/plugins/dev_tools/public/application.tsx | 1 + src/plugins/dev_tools/public/index.scss | 8 +++++++- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/7347.yml diff --git a/changelogs/fragments/7347.yml b/changelogs/fragments/7347.yml new file mode 100644 index 000000000000..075f9d718446 --- /dev/null +++ b/changelogs/fragments/7347.yml @@ -0,0 +1,2 @@ +fix: +- Data source selector in dev tools tab moved to left ([#7347](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7347)) \ No newline at end of file diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx index b1ccd290e59a..6c4cae6e18cf 100644 --- a/src/plugins/dev_tools/public/application.tsx +++ b/src/plugins/dev_tools/public/application.tsx @@ -124,6 +124,7 @@ function DevToolsWrapper({ onSelectedDataSource={onChange} disabled={!dataSourceEnabled} fullWidth={false} + compressed />
); diff --git a/src/plugins/dev_tools/public/index.scss b/src/plugins/dev_tools/public/index.scss index 554452a8923e..69754c302ff9 100644 --- a/src/plugins/dev_tools/public/index.scss +++ b/src/plugins/dev_tools/public/index.scss @@ -23,6 +23,12 @@ } .devAppDataSourceSelector { - margin: 7px 8px 0 0; + margin: 4px 8px 0 0; min-width: 400px; + margin-left: auto; +} + +.devAppTabs { + display: flex; + flex-flow: row wrap; } From d89447ba807639d4992ccda4b1d782e321c23cca Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 10:42:18 -0700 Subject: [PATCH 098/276] [navigation-next] feat: add recent works in new homepage (#7237) (#7362) * Changeset file for PR #7237 created/updated * feat: remove the euispacer * feat: update empty state * feat: update i18n key * feat: update --------- (cherry picked from commit 46afb96cdf57b53683457c4dde98bbf6ae155bfe) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7237.yml | 2 + src/core/public/chrome/index.ts | 7 +- .../recently_accessed_service.ts | 19 +- src/core/public/chrome/ui/header/index.ts | 1 + src/core/public/chrome/ui/index.ts | 1 + src/core/public/index.ts | 2 + .../use/use_saved_dashboard_instance.test.ts | 1 + .../utils/use/use_saved_dashboard_instance.ts | 3 +- .../view_components/utils/use_search.ts | 5 +- .../discover/public/saved_searches/types.ts | 9 +- .../home/public/application/home_render.tsx | 14 +- .../saved_object/helpers/save_saved_object.ts | 5 +- .../opensearch_dashboards.json | 3 +- .../management_section/recent_work.test.tsx | 98 +++++++ .../public/management_section/recent_work.tsx | 276 ++++++++++++++++++ .../saved_objects_management/public/plugin.ts | 25 +- .../utils/use/use_saved_vis_builder_vis.ts | 7 + .../public/saved_visualizations/_saved_vis.ts | 1 + .../utils/use/use_saved_vis_instance.test.ts | 2 + .../utils/use/use_saved_vis_instance.ts | 8 + 20 files changed, 479 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/7237.yml create mode 100644 src/plugins/saved_objects_management/public/management_section/recent_work.test.tsx create mode 100644 src/plugins/saved_objects_management/public/management_section/recent_work.tsx diff --git a/changelogs/fragments/7237.yml b/changelogs/fragments/7237.yml new file mode 100644 index 000000000000..28da091c7e1d --- /dev/null +++ b/changelogs/fragments/7237.yml @@ -0,0 +1,2 @@ +feat: +- [navigation-next] add recent works in new homepage ([#7237](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7237)) \ No newline at end of file diff --git a/src/core/public/chrome/index.ts b/src/core/public/chrome/index.ts index 02100ce4f63a..d37f14dc9e8a 100644 --- a/src/core/public/chrome/index.ts +++ b/src/core/public/chrome/index.ts @@ -44,7 +44,12 @@ export { ChromeHelpExtensionMenuDocumentationLink, ChromeHelpExtensionMenuGitHubLink, } from './ui/header/header_help_menu'; -export { NavType, RightNavigationButton, RightNavigationButtonProps } from './ui'; +export { + NavType, + RightNavigationButton, + RightNavigationButtonProps, + createRecentNavLink, +} from './ui'; export { ChromeNavLink, ChromeNavLinks, ChromeNavLinkUpdateableFields } from './nav_links'; export { ChromeRecentlyAccessed, diff --git a/src/core/public/chrome/recently_accessed/recently_accessed_service.ts b/src/core/public/chrome/recently_accessed/recently_accessed_service.ts index e111d71d25d6..99ca61513855 100644 --- a/src/core/public/chrome/recently_accessed/recently_accessed_service.ts +++ b/src/core/public/chrome/recently_accessed/recently_accessed_service.ts @@ -41,6 +41,10 @@ export interface ChromeRecentlyAccessedHistoryItem { label: string; id: string; workspaceId?: string; + meta?: { + type?: string; + lastAccessedTime?: number; + }; } interface StartDeps { @@ -59,7 +63,12 @@ export class RecentlyAccessedService { return { /** Adds a new item to the history. */ - add: (link: string, label: string, id: string) => { + add: ( + link: string, + label: string, + id: string, + meta?: ChromeRecentlyAccessedHistoryItem['meta'] + ) => { const currentWorkspaceId = workspaces.currentWorkspaceId$.getValue(); history.add({ @@ -67,6 +76,7 @@ export class RecentlyAccessedService { label, id, ...(currentWorkspaceId && { workspaceId: currentWorkspaceId }), + ...(meta && { meta: { lastAccessedTime: Date.now(), ...meta } }), }); }, @@ -96,7 +106,12 @@ export interface ChromeRecentlyAccessed { * @param label the label to display in the UI * @param id a unique string used to de-duplicate the recently accessed list. */ - add(link: string, label: string, id: string): void; + add( + link: string, + label: string, + id: string, + meta?: ChromeRecentlyAccessedHistoryItem['meta'] + ): void; /** * Gets an Array of the current recently accessed history. diff --git a/src/core/public/chrome/ui/header/index.ts b/src/core/public/chrome/ui/header/index.ts index 811eca0cad84..a43a3e7470d2 100644 --- a/src/core/public/chrome/ui/header/index.ts +++ b/src/core/public/chrome/ui/header/index.ts @@ -38,3 +38,4 @@ export { ChromeHelpExtensionMenuGitHubLink, } from './header_help_menu'; export { RightNavigationButton, RightNavigationButtonProps } from './right_navigation_button'; +export { createRecentNavLink } from './nav_link'; diff --git a/src/core/public/chrome/ui/index.ts b/src/core/public/chrome/ui/index.ts index 11f0c0302df5..963f54571323 100644 --- a/src/core/public/chrome/ui/index.ts +++ b/src/core/public/chrome/ui/index.ts @@ -39,4 +39,5 @@ export { NavType, RightNavigationButton, RightNavigationButtonProps, + createRecentNavLink, } from './header'; diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 8c387361a9ca..9da3aed89736 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -76,6 +76,7 @@ import { PersistedLog, NavGroupItemInMap, fulfillRegistrationLinksToChromeNavLinks, + createRecentNavLink, } from './chrome'; import { FatalErrorsSetup, FatalErrorsStart, FatalErrorInfo } from './fatal_errors'; import { HttpSetup, HttpStart } from './http'; @@ -379,6 +380,7 @@ export { PersistedLog, NavGroupItemInMap, fulfillRegistrationLinksToChromeNavLinks, + createRecentNavLink, }; export { __osdBootstrap__ } from './osd_bootstrap'; diff --git a/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.test.ts b/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.test.ts index b7b69a39de5c..2b1ab3e1c86f 100644 --- a/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.test.ts +++ b/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.test.ts @@ -38,6 +38,7 @@ describe('useSavedDashboardInstance', () => { getFilters: () => dashboardAppStateStub.filters, optionsJSON: JSON.stringify(dashboardAppStateStub.options), getFullPath: () => `/${dashboardIdFromUrl}`, + getOpenSearchType: () => 'dashboard', }, } as unknown) as SavedObjectDashboard; dashboard = new Dashboard(convertToSerializedDashboard(savedDashboardInstance)); diff --git a/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts b/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts index 7cc0a46b2a55..fedc353f3e2c 100644 --- a/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts +++ b/src/plugins/dashboard/public/application/utils/use/use_saved_dashboard_instance.ts @@ -129,7 +129,8 @@ export const useSavedDashboardInstance = ({ chrome.recentlyAccessed.add( savedDashboard.getFullPath(), savedDashboard.title, - dashboardIdFromUrl + dashboardIdFromUrl, + { type: savedDashboard.getOpenSearchType() } ); setSavedDashboardInstance(dashboardInstance); } catch (error: any) { diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index 4de9e987bd53..8c2ace81b048 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -309,7 +309,10 @@ export const useSearch = (services: DiscoverViewServices) => { chrome.recentlyAccessed.add( savedSearchInstance.getFullPath(), savedSearchInstance.title, - savedSearchInstance.id + savedSearchInstance.id, + { + type: savedSearchInstance.getOpenSearchType(), + } ); } })(); diff --git a/src/plugins/discover/public/saved_searches/types.ts b/src/plugins/discover/public/saved_searches/types.ts index 73cb25774c4a..f013eab77ed2 100644 --- a/src/plugins/discover/public/saved_searches/types.ts +++ b/src/plugins/discover/public/saved_searches/types.ts @@ -36,7 +36,14 @@ export type SortOrder = [string, SortDirection]; export interface SavedSearch extends Pick< SavedObject, - 'id' | 'title' | 'copyOnSave' | 'destroy' | 'lastSavedTitle' | 'save' | 'getFullPath' + | 'id' + | 'title' + | 'copyOnSave' + | 'destroy' + | 'lastSavedTitle' + | 'save' + | 'getFullPath' + | 'getOpenSearchType' > { searchSource: ISearchSource; // This is optional in SavedObject, but required for SavedSearch description?: string; diff --git a/src/plugins/home/public/application/home_render.tsx b/src/plugins/home/public/application/home_render.tsx index 49d5bd1c9043..86292469cc7a 100644 --- a/src/plugins/home/public/application/home_render.tsx +++ b/src/plugins/home/public/application/home_render.tsx @@ -26,7 +26,19 @@ export const setupHome = (contentManagement: ContentManagementPluginSetup) => { order: 2000, title: 'Recently viewed', kind: 'custom', - render: () => <>, + render: (contents) => { + return ( + <> + {contents.map((content) => { + if (content.kind === 'custom') { + return content.render(); + } + + return null; + })} + + ); + }, }, { id: SECTIONS.GET_STARTED, diff --git a/src/plugins/saved_objects/public/saved_object/helpers/save_saved_object.ts b/src/plugins/saved_objects/public/saved_object/helpers/save_saved_object.ts index 01be4f97591e..2e75ff3dd44f 100644 --- a/src/plugins/saved_objects/public/saved_object/helpers/save_saved_object.ts +++ b/src/plugins/saved_objects/public/saved_object/helpers/save_saved_object.ts @@ -123,7 +123,10 @@ export async function saveSavedObject( chrome.recentlyAccessed.add( savedObject.getFullPath(), savedObject.title, - String(savedObject.id) + String(savedObject.id), + { + type: savedObject.getOpenSearchType(), + } ); } savedObject.isSaving = false; diff --git a/src/plugins/saved_objects_management/opensearch_dashboards.json b/src/plugins/saved_objects_management/opensearch_dashboards.json index 225fe67e9f57..2802eb04b3dc 100644 --- a/src/plugins/saved_objects_management/opensearch_dashboards.json +++ b/src/plugins/saved_objects_management/opensearch_dashboards.json @@ -12,7 +12,8 @@ "visBuilder", "visAugmenter", "dataSource", - "dataSourceManagement" + "dataSourceManagement", + "contentManagement" ], "extraPublicDirs": ["public/lib"], "requiredBundles": ["opensearchDashboardsReact", "home"] diff --git a/src/plugins/saved_objects_management/public/management_section/recent_work.test.tsx b/src/plugins/saved_objects_management/public/management_section/recent_work.test.tsx new file mode 100644 index 000000000000..6441ce280f68 --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/recent_work.test.tsx @@ -0,0 +1,98 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { BehaviorSubject } from 'rxjs'; +import { fireEvent, render } from '@testing-library/react'; +import { RecentWork } from './recent_work'; +import { coreMock } from '../../../../core/public/mocks'; +import { ChromeRecentlyAccessedHistoryItem } from 'opensearch-dashboards/public'; +import { SavedObjectWithMetadata } from '../types'; + +const mockedRecentItems: ChromeRecentlyAccessedHistoryItem[] = [ + { + link: '/app/visualize', + label: 'visualize', + id: 'visualize', + meta: { + type: 'visualize', + }, + }, + { + link: '/app/dashboard', + label: 'dashboard', + id: 'dashboard-in-workspace', + workspaceId: 'workspace-id', + meta: { + type: 'dashboard', + }, + }, +]; + +const savedObjectsFromServer: SavedObjectWithMetadata[] = [ + { + type: 'visualize', + id: 'visualize', + attributes: {}, + references: [], + updated_at: '2024-07-20T00:00:00.000Z', + meta: {}, + }, + { + type: 'dashboard', + id: 'dashboard-in-workspace', + attributes: {}, + references: [], + updated_at: '2024-07-20T00:00:01.000Z', + meta: {}, + }, +]; + +const getStartMockForRecentWork = () => { + const coreStartMock = coreMock.createStart(); + coreStartMock.chrome.recentlyAccessed.get$.mockReturnValue(new BehaviorSubject([])); + coreStartMock.chrome.navLinks.getNavLinks$.mockReturnValue(new BehaviorSubject([])); + return coreStartMock; +}; + +describe('', () => { + it('render with emty recent work', async () => { + const { findByText } = render(); + await findByText('No recent work'); + }); + + it('render with recent works', async () => { + const coreStartMock = getStartMockForRecentWork(); + coreStartMock.http.get.mockImplementation((url) => { + if (typeof url === 'string') { + if ((url as string).includes(mockedRecentItems[0].id)) { + return Promise.resolve(savedObjectsFromServer[0]); + } else { + return Promise.resolve(savedObjectsFromServer[1]); + } + } + + return Promise.reject({}); + }); + + coreStartMock.chrome.recentlyAccessed.get$.mockReturnValue( + new BehaviorSubject(mockedRecentItems) + ); + + const { findAllByTestId, getByTestId } = render(); + const allCards = await findAllByTestId('recentlyCard'); + expect(allCards.length).toBe(2); + expect(allCards[0].querySelector('.euiCard__titleAnchor')?.textContent).toEqual( + mockedRecentItems[0].label + ); + + // click the filter button + fireEvent.click(getByTestId('filterButton-recently%20updated')); + const allCardsAfterSort = await findAllByTestId('recentlyCard'); + expect(allCardsAfterSort[0].querySelector('.euiCard__titleAnchor')?.textContent).toEqual( + mockedRecentItems[1].label + ); + }); +}); diff --git a/src/plugins/saved_objects_management/public/management_section/recent_work.tsx b/src/plugins/saved_objects_management/public/management_section/recent_work.tsx new file mode 100644 index 000000000000..2e5b45e2cd63 --- /dev/null +++ b/src/plugins/saved_objects_management/public/management_section/recent_work.tsx @@ -0,0 +1,276 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useMemo, useState, useEffect, useRef } from 'react'; +import moment from 'moment'; +import { + EuiFlexItem, + EuiCard, + EuiPanel, + EuiSpacer, + EuiFlexGroup, + EuiTitle, + EuiFilterGroup, + EuiFilterButton, + EuiComboBox, + EuiIcon, + EuiEmptyPrompt, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { + ChromeRecentlyAccessedHistoryItem, + CoreStart, + SavedObject, +} from 'opensearch-dashboards/public'; +import { useObservable } from 'react-use'; +import { SavedObjectWithMetadata } from 'src/plugins/saved_objects_management/common'; +import { createRecentNavLink } from '../../../../core/public'; + +const allOption = i18n.translate('savedObjectsManagement.recentWorkSection.all.items', { + defaultMessage: 'all items', +}); + +const recentlyViewed = i18n.translate('savedObjectsManagement.recentWorkSection.recentlyViewed', { + defaultMessage: 'recently viewed', +}); + +const recentlyUpdated = i18n.translate('savedObjectsManagement.recentWorkSection.recentlyUpdated', { + defaultMessage: 'recently updated', +}); + +const sortKeyMap = { + [recentlyViewed]: 'lastAccessedTime', + [recentlyUpdated]: 'updatedAt', +} as const; + +type KeyOf = keyof T; + +function sortBy(key: KeyOf) { + return (a: T, b: T): number => (a[key] > b[key] ? -1 : b[key] > a[key] ? 1 : 0); +} + +type DetailedRecentlyAccessedItem = ChromeRecentlyAccessedHistoryItem & + SavedObjectWithMetadata & + ChromeRecentlyAccessedHistoryItem['meta'] & { + updatedAt: number; + workspaceName?: string; + }; + +const bulkGetDetail = ( + savedObjects: Array>, + http: CoreStart['http'] +) => { + return Promise.all( + savedObjects.map((obj) => + http + .get( + `/api/opensearch-dashboards/management/saved_objects/${encodeURIComponent( + obj.type + )}/${encodeURIComponent(obj.id)}` + ) + .catch((error) => ({ + id: obj.id, + type: obj.type, + error, + attributes: {}, + references: [], + meta: {}, + updated_at: '', + })) + ) + ); +}; + +const widthForTypeSelector = 220; +const widthForRightMargin = 4; +const MAX_ITEMS_DISPLAY = 6; + +export const RecentWork = (props: { core: CoreStart; workspaceEnabled?: boolean }) => { + const { core, workspaceEnabled } = props; + const recently$Ref = useRef(core.chrome.recentlyAccessed.get$()); + const recentAccessed = useObservable(recently$Ref.current, []); + const workspaceList = useObservable(core.workspaces.workspaceList$, []); + const [selectedType, setSelectedType] = useState(allOption); + const [selectedSort, setSelectedSort] = useState(recentlyViewed); + const [detailedSavedObjects, setDetailedSavedObjects] = useState( + [] + ); + + const allOptions = useMemo(() => { + const options: string[] = [allOption]; + detailedSavedObjects + .filter((item) => !item.error) + .forEach((recentAccessItem: ChromeRecentlyAccessedHistoryItem) => { + if (recentAccessItem.meta?.type && options.indexOf(recentAccessItem.meta.type) === -1) { + options.push(recentAccessItem.meta.type); + } + }); + return options.map((option: string) => ({ label: option, value: option })); + }, [detailedSavedObjects]); + + const itemsForDisplay = useMemo(() => { + const sortedResult = [...detailedSavedObjects] + .filter((item) => !item.error) + .sort(sortBy(sortKeyMap[selectedSort])); + return sortedResult.filter((item: SavedObject & ChromeRecentlyAccessedHistoryItem) => { + if (selectedType === allOption) return true; + return item.type === selectedType; + }); + }, [detailedSavedObjects, selectedSort, selectedType]); + + useEffect(() => { + const savedObjects = recentAccessed + .filter((item) => item.meta?.type) + .map((item) => ({ + type: item.meta?.type || '', + id: item.id, + })); + + if (savedObjects.length) { + bulkGetDetail(savedObjects, core.http).then((res) => { + const formatDetailedSavedObjects = res.map((obj) => { + const recentAccessItem = recentAccessed.find( + (item) => item.id === obj.id + ) as ChromeRecentlyAccessedHistoryItem; + + const findWorkspace = workspaceList.find( + (workspace) => workspace.id === recentAccessItem.workspaceId + ); + + return { + ...recentAccessItem, + ...obj, + ...recentAccessItem.meta, + updatedAt: moment(obj?.updated_at).valueOf(), + workspaceName: findWorkspace?.name, + }; + }); + setDetailedSavedObjects(formatDetailedSavedObjects); + }); + } + }, [core.savedObjects.client, recentAccessed, core.http, workspaceList]); + + return ( + + + + +
+ {i18n.translate('savedObjectsManagement.recentWorkSection.title', { + defaultMessage: 'Assets', + })} +
+
+
+ + + + + {[recentlyViewed, recentlyUpdated].map((item) => ( + setSelectedSort(item)} + data-test-subj={`filterButton-${encodeURIComponent(item)}`} + > + {item} + + ))} + + + + setSelectedType(options[0].value || '')} + selectedOptions={[{ label: selectedType, value: selectedType }]} + /> + + + +
+ {itemsForDisplay.length ? ( + + {Array.from({ length: MAX_ITEMS_DISPLAY }).map((item, itemIndexInRow) => { + const recentAccessItem = itemsForDisplay[itemIndexInRow]; + let content = null; + if (recentAccessItem) { + const navLinks = core.chrome.navLinks.getAll(); + const recentNavLink = createRecentNavLink( + recentAccessItem, + navLinks, + core.http.basePath, + core.application.navigateToUrl + ); + content = ( + +
+ + {recentAccessItem.type} +
+ +
+ {selectedSort === recentlyViewed + ? i18n.translate('savedObjectsManagement.recentWorkSection.viewedAt', { + defaultMessage: 'Viewed', + }) + : i18n.translate('savedObjectsManagement.recentWorkSection.updatedAt', { + defaultMessage: 'Updated', + })} + :{' '} + + {selectedSort === recentlyViewed + ? moment(recentAccessItem?.lastAccessedTime).fromNow() + : moment(recentAccessItem?.updatedAt).fromNow()} + +
+ {workspaceEnabled && ( +
+ {i18n.translate('savedObjectsManagement.recentWorkSection.workspace', { + defaultMessage: 'Workspace', + })} + : {recentAccessItem.workspaceName || 'N/A'} +
+ )} + + } + onClick={recentNavLink.onClick} + /> + ); + } + return ( + {content} + ); + })} +
+ ) : ( + + {i18n.translate('savedObjectsManagement.recentWorkSection.empty.title', { + defaultMessage: 'No recent work', + })} +

+ } + /> + )} + + ); +}; diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index 5815874390fb..1247b56b5555 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -28,10 +28,12 @@ * under the License. */ +import React from 'react'; import { i18n } from '@osd/i18n'; import { AppMountParameters, CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { DataSourcePluginSetup } from 'src/plugins/data_source/public'; +import { ContentManagementPluginStart } from 'src/plugins/content_management/public'; import { DataSourceManagementPluginSetup } from 'src/plugins/data_source_management/public'; import { VisBuilderStart } from '../../vis_builder/public'; import { ManagementSetup } from '../../management/public'; @@ -62,6 +64,8 @@ import { import { registerServices } from './register_services'; import { bootstrap } from './ui_actions_bootstrap'; import { DEFAULT_NAV_GROUPS, DEFAULT_APP_CATEGORIES } from '../../../core/public'; +import { RecentWork } from './management_section/recent_work'; +import { HOME_CONTENT_AREAS } from '../../../plugins/home/public'; export interface SavedObjectsManagementPluginSetup { actions: SavedObjectsManagementActionServiceSetup; @@ -93,6 +97,7 @@ export interface StartDependencies { discover?: DiscoverStart; visBuilder?: VisBuilderStart; uiActions: UiActionsStart; + contentManagement?: ContentManagementPluginStart; } export class SavedObjectsManagementPlugin @@ -239,10 +244,28 @@ export class SavedObjectsManagementPlugin }; } - public start(core: CoreStart, { data, uiActions }: StartDependencies) { + public start(core: CoreStart, { data, uiActions, contentManagement }: StartDependencies) { const actionStart = this.actionService.start(); const columnStart = this.columnService.start(); const namespaceStart = this.namespaceService.start(); + const workspaceEnabled = core.application.capabilities.workspaces.enabled; + + contentManagement?.registerContentProvider({ + id: 'recent', + getContent: () => { + return { + order: 1, + id: 'recent', + kind: 'custom', + render: () => + React.createElement(RecentWork, { + core, + workspaceEnabled, + }), + }; + }, + getTargetArea: () => HOME_CONTENT_AREAS.RECENTLY_VIEWED, + }); return { actions: actionStart, 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 3ec69902c9c2..8f67b8d2358f 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 @@ -74,6 +74,13 @@ export const useSavedVisBuilderVis = (visualizationIdFromUrl: string | undefined data.query.filterManager.setAppFilters(actualFilters); data.query.queryString.setQuery(query); + chrome.recentlyAccessed.add( + savedVisBuilderVis.getFullPath(), + title, + savedVisBuilderVis.id, + { type: savedVisBuilderVis.getOpenSearchType() } + ); + dispatch(setUIStateState(state.ui)); dispatch(setStyleState(state.style)); dispatch(setVisualizationState(state.visualization)); diff --git a/src/plugins/vis_builder/public/saved_visualizations/_saved_vis.ts b/src/plugins/vis_builder/public/saved_visualizations/_saved_vis.ts index 021af777df17..18a8a472c7fa 100644 --- a/src/plugins/vis_builder/public/saved_visualizations/_saved_vis.ts +++ b/src/plugins/vis_builder/public/saved_visualizations/_saved_vis.ts @@ -51,6 +51,7 @@ export function createSavedVisBuilderVisClass(services: SavedObjectOpenSearchDas }); this.showInRecentlyAccessed = true; this.getFullPath = () => `/app/${PLUGIN_ID}${EDIT_PATH}/${this.id}`; + this.getOpenSearchType = () => VISBUILDER_SAVED_OBJECT; } } diff --git a/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.test.ts b/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.test.ts index 46d616d06730..0dbbf182df2b 100644 --- a/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.test.ts +++ b/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.test.ts @@ -52,6 +52,8 @@ const mockSavedVisInstance = { id: savedVisId, title: 'Test Vis', destroy: mockSavedVisDestroy, + getOpenSearchType: () => 'visualization', + getFullPath: () => '/', }, vis: { type: {}, diff --git a/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.ts b/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.ts index c80b2b1afd5d..2438f26a648e 100644 --- a/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.ts +++ b/src/plugins/visualize/public/application/utils/use/use_saved_vis_instance.ts @@ -107,6 +107,14 @@ export const useSavedVisInstance = ( if (savedVis.id) { chrome.setBreadcrumbs(getEditBreadcrumbs(savedVis.title)); chrome.docTitle.change(savedVis.title); + chrome.recentlyAccessed.add( + savedVisInstance.savedVis.getFullPath(), + savedVisInstance.savedVis.title, + savedVis.id, + { + type: savedVisInstance.savedVis.getOpenSearchType(), + } + ); } else { chrome.setBreadcrumbs(getCreateBreadcrumbs()); } From b1e5237da6dba7137a092143e91724162bc3eb91 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:23:15 -0700 Subject: [PATCH 099/276] Add Drag & Drop Across Axis Functionality to Vis Builder (#7107) (#7266) * Add Drag Across Axis Functionality to Vis Builder * Changeset file for PR #7107 created/updated --------- (cherry picked from commit 27669cff48cd404e480310f232a0bb0f6b988aed) Signed-off-by: Suchit Sahoo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7107.yml | 2 + .../components/data_tab/config_panel.tsx | 45 ++++-- .../components/data_tab/constants.ts | 11 ++ .../drag_drop/add_field_to_configuration.ts | 67 +++++++++ .../drag_drop/move_field_between_schemas.ts | 63 ++++++++ .../drag_drop/reorder_fields_within_schema.ts | 40 +++++ .../replace_field_in_configuration.ts | 80 ++++++++++ .../components/data_tab/dropbox.scss | 4 + .../components/data_tab/dropbox.tsx | 133 ++++++++--------- .../components/data_tab/field.test.tsx | 9 +- .../application/components/data_tab/field.tsx | 33 ++++- .../components/data_tab/field_selector.scss | 2 - .../data_tab/field_selector.test.tsx | 9 +- .../components/data_tab/field_selector.tsx | 106 +++++++------ .../application/components/data_tab/index.tsx | 139 +++++++++++++++++- .../components/data_tab/schema_to_dropbox.tsx | 22 ++- .../components/data_tab/use/use_dropbox.tsx | 84 ++++++----- .../data_tab/utils/get_valid_aggregations.tsx | 99 +++++++++++++ .../components/draggable_accordion.scss | 34 +++++ .../components/draggable_accordion.tsx | 59 ++++++++ 20 files changed, 855 insertions(+), 186 deletions(-) create mode 100644 changelogs/fragments/7107.yml create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/constants.ts create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/drag_drop/add_field_to_configuration.ts create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/drag_drop/move_field_between_schemas.ts create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/drag_drop/reorder_fields_within_schema.ts create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/drag_drop/replace_field_in_configuration.ts create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/utils/get_valid_aggregations.tsx create mode 100644 src/plugins/vis_builder/public/application/components/draggable_accordion.scss create mode 100644 src/plugins/vis_builder/public/application/components/draggable_accordion.tsx diff --git a/changelogs/fragments/7107.yml b/changelogs/fragments/7107.yml new file mode 100644 index 000000000000..163246e04698 --- /dev/null +++ b/changelogs/fragments/7107.yml @@ -0,0 +1,2 @@ +feat: +- Enhance Drag & Drop functionality in Vis Builder ([#7107](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7107)) \ No newline at end of file diff --git a/src/plugins/vis_builder/public/application/components/data_tab/config_panel.tsx b/src/plugins/vis_builder/public/application/components/data_tab/config_panel.tsx index ec3b6b60a096..ae9067cd676e 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/config_panel.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/config_panel.tsx @@ -5,22 +5,49 @@ import { EuiForm } from '@elastic/eui'; import React from 'react'; -import { useVisualizationType } from '../../utils/use'; -import { useTypedSelector } from '../../utils/state_management'; + import './config_panel.scss'; import { mapSchemaToAggPanel } from './schema_to_dropbox'; import { SecondaryPanel } from './secondary_panel'; +import { Schemas } from '../../../../../vis_default_editor/public'; +import { + AggConfig, + AggConfigs, + CreateAggConfigParams, +} from '../../../../../data/common/search/aggs'; +import { IndexPattern, TimeRange } from '../../../../../data/public'; +import { SchemaDisplayStates } from '.'; -export function ConfigPanel() { - const vizType = useVisualizationType(); - const editingState = useTypedSelector( - (state) => state.visualization.activeVisualization?.draftAgg - ); - const schemas = vizType.ui.containerConfig.data.schemas; +export interface AggProps { + indexPattern: IndexPattern | undefined; + aggConfigs: AggConfigs | undefined; + aggs: AggConfig[]; + timeRange: TimeRange; +} +export interface ConfigPanelProps { + schemas: Schemas; + editingState?: CreateAggConfigParams; + aggProps: AggProps; + activeSchemaFields: SchemaDisplayStates; + setActiveSchemaFields: React.Dispatch>; +} + +export function ConfigPanel({ + schemas, + editingState, + aggProps, + activeSchemaFields, + setActiveSchemaFields, +}: ConfigPanelProps) { if (!schemas) return null; - const mainPanel = mapSchemaToAggPanel(schemas); + const mainPanel = mapSchemaToAggPanel( + schemas, + aggProps, + activeSchemaFields, + setActiveSchemaFields + ); return ( diff --git a/src/plugins/vis_builder/public/application/components/data_tab/constants.ts b/src/plugins/vis_builder/public/application/components/data_tab/constants.ts new file mode 100644 index 000000000000..9369bd78e143 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/constants.ts @@ -0,0 +1,11 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export enum FIELD_SELECTOR_ID { + COUNT = 'preDefinedCountMetric', + CATEGORICAL = 'categoricalFields', + NUMERICAL = 'numericalFields', + META = 'metaFields', +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/add_field_to_configuration.ts b/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/add_field_to_configuration.ts new file mode 100644 index 000000000000..e8df5654f46c --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/add_field_to_configuration.ts @@ -0,0 +1,67 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { DropResult } from '@elastic/eui'; +import { AnyAction } from 'redux'; +import { createNewAggConfig } from '../utils/get_valid_aggregations'; +import { updateAggConfigParams } from '../../../utils/state_management/visualization_slice'; +import { Schemas } from '../../../../../../vis_default_editor/public'; +import { AggProps } from '../config_panel'; +import { SchemaDisplayStates } from '../index'; +import { Dispatch } from '../../../../../../opensearch_dashboards_utils/common/state_containers/types'; +import { AggsStart } from '../../../../../../data/common'; + +export interface DragDropProperties { + dropResult: DropResult; + schemas: Schemas; + aggProps: AggProps; + aggService: AggsStart; + activeSchemaFields: SchemaDisplayStates; + dispatch: Dispatch; +} + +export function addFieldToConfiguration({ + dropResult, + schemas, + aggProps, + aggService, + activeSchemaFields, + dispatch, +}: DragDropProperties) { + const { source, destination, combine, draggableId } = dropResult; + + const destinationSchemaName = destination?.droppableId; + const destinationSchema = schemas.all.find((schema) => schema.name === destinationSchemaName); + + const newFieldToAdd = draggableId; + + if (!destinationSchema || !destinationSchemaName) { + // Invalid drop target selected + return; + } + + const destinationFields = activeSchemaFields[destinationSchemaName]; + + if (!combine && destination && destinationFields.length > destinationSchema?.max) { + // Can't Add additional Fields + return; + } + + // Adding the new field + createNewAggConfig({ + fieldName: newFieldToAdd, + sourceGroup: source.droppableId, + destinationSchema, + aggProps, + aggService, + sourceAgg: null, + }); + + const updatedAggConfigs = aggProps.aggConfigs?.aggs; + + if (updatedAggConfigs) { + dispatch(updateAggConfigParams(updatedAggConfigs.map((agg) => agg.serialize()))); + } +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/move_field_between_schemas.ts b/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/move_field_between_schemas.ts new file mode 100644 index 000000000000..6f02c2cf0f5a --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/move_field_between_schemas.ts @@ -0,0 +1,63 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { updateAggConfigParams } from '../../../utils/state_management/visualization_slice'; +import { createNewAggConfig } from '../utils/get_valid_aggregations'; +import { DragDropProperties } from './add_field_to_configuration'; + +export function moveFieldBetweenSchemas({ + dropResult, + schemas, + aggProps, + aggService, + activeSchemaFields, + dispatch, +}: DragDropProperties) { + const { source, destination, combine, draggableId } = dropResult; + + const destinationSchemaName = destination?.droppableId; + if (!destinationSchemaName) { + // Invalid Transition + return; + } + const sourceAggId = draggableId; + + const destinationSchema = schemas.all.find( + (schema) => schema.name === (destination?.droppableId || combine?.droppableId) + ); + + if (!destinationSchema) { + // Invalid Transition + return; + } + + const sourceAgg = aggProps.aggConfigs?.aggs.find((agg) => agg.id === sourceAggId); + const sourceFieldName = sourceAgg?.fieldName(); + + const destinationAggFields = activeSchemaFields[destinationSchemaName]; + + const destinationLimit = destinationSchema?.max; + + if (destinationLimit && destinationAggFields.length <= destinationLimit) { + // destination schema has space for more items to be added + // We Need to update sourceAgg + + createNewAggConfig({ + fieldName: sourceFieldName, + sourceGroup: source.droppableId, + destinationSchema, + aggProps, + aggService, + sourceAgg, + }); + + // Remove the sourceAggConfig from the updated Config + const updatedAggConfig = aggProps.aggConfigs?.aggs.filter((agg) => agg.id !== sourceAggId); + + if (updatedAggConfig?.length) { + dispatch(updateAggConfigParams(updatedAggConfig.map((agg) => agg.serialize()))); + } + } +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/reorder_fields_within_schema.ts b/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/reorder_fields_within_schema.ts new file mode 100644 index 000000000000..b6d83ff07ea4 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/reorder_fields_within_schema.ts @@ -0,0 +1,40 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { reorderAgg } from '../../../utils/state_management/visualization_slice'; +import { DragDropProperties } from './add_field_to_configuration'; + +export function reorderFieldsWithinSchema({ + dropResult, + schemas, + activeSchemaFields, + dispatch, +}: DragDropProperties) { + const { destination, draggableId } = dropResult; + + const destinationSchemaName = destination?.droppableId; + if (!destinationSchemaName) { + // Invalid Transition + return; + } + const destinationAggFields = activeSchemaFields[destinationSchemaName]; + + const sourceAggId = draggableId; + const destinationAggId = destinationAggFields[destination?.index].id; + + const destinationSchema = schemas.all.find((schema) => schema.name === destination?.droppableId); + + if (!destinationSchema) { + // Invalid Transition + return; + } + + dispatch( + reorderAgg({ + sourceId: sourceAggId, + destinationId: destinationAggId, + }) + ); +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/replace_field_in_configuration.ts b/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/replace_field_in_configuration.ts new file mode 100644 index 000000000000..316d9570899c --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/drag_drop/replace_field_in_configuration.ts @@ -0,0 +1,80 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { updateAggConfigParams } from '../../../utils/state_management/visualization_slice'; +import { FIELD_SELECTOR_ID } from '../constants'; +import { createNewAggConfig } from '../utils/get_valid_aggregations'; +import { DragDropProperties } from './add_field_to_configuration'; + +export function replaceFieldInConfiguration({ + dropResult, + schemas, + aggProps, + aggService, + dispatch, +}: DragDropProperties) { + const { source, combine, draggableId } = dropResult; + + const destinationSchemaName = combine?.droppableId; + if (!destinationSchemaName) { + return; + } + + const sourceAggId = draggableId; + const destinationAggId = combine?.draggableId; + + const destinationSchema = schemas.all.find((schema) => schema.name === combine?.droppableId); + + if (!destinationSchema) { + // Invalid Transition + return; + } + + const sourceSchema = source.droppableId; + + if (Object.values(FIELD_SELECTOR_ID).includes(sourceSchema as FIELD_SELECTOR_ID)) { + // Replacing an exisitng configuration with a new field from field selector panel + + const newFieldToAdd = draggableId; + createNewAggConfig({ + fieldName: newFieldToAdd, + sourceGroup: source.droppableId, + destinationSchema, + aggProps, + aggService, + sourceAgg: null, + }); + + // Removing the exisiting destination Aggregation + const updatedAggConfig = aggProps.aggConfigs?.aggs.filter((agg) => agg.id !== destinationAggId); + + if (updatedAggConfig) { + dispatch(updateAggConfigParams(updatedAggConfig.map((agg) => agg.serialize()))); + } + } else { + // Replacing an existing configuration with another exisiting configuration + + const sourceAgg = aggProps.aggConfigs?.aggs.find((agg) => agg.id === sourceAggId); + const sourceFieldName = sourceAgg?.fieldName(); + + createNewAggConfig({ + fieldName: sourceFieldName, + sourceGroup: source.droppableId, + destinationSchema, + aggProps, + aggService, + sourceAgg, + }); + + // Removing the exisiting destination and source Aggregation + const updatedAggConfig = aggProps.aggConfigs?.aggs.filter( + (agg) => agg.id !== destinationAggId && agg.id !== sourceAggId + ); + + if (updatedAggConfig) { + dispatch(updateAggConfigParams(updatedAggConfig.map((agg) => agg.serialize()))); + } + } +} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/dropbox.scss b/src/plugins/vis_builder/public/application/components/data_tab/dropbox.scss index 89c7832ac40a..a92639420b1c 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/dropbox.scss +++ b/src/plugins/vis_builder/public/application/components/data_tab/dropbox.scss @@ -15,6 +15,10 @@ border-bottom: none; } + &__droppable { + min-height: 1px; + } + &__container { display: grid; grid-gap: calc($euiSizeXS / 2); 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 70b43a2c6014..e5b46b589e0f 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 @@ -6,13 +6,11 @@ import { i18n } from '@osd/i18n'; import { EuiButtonIcon, - EuiDragDropContext, EuiDraggable, EuiDroppable, EuiFormRow, EuiPanel, EuiText, - DropResult, } from '@elastic/eui'; import React, { useCallback, useState } from 'react'; import { IDropAttributes, IDropState } from '../../utils/drag_drop'; @@ -51,7 +49,6 @@ const DropboxComponent = ({ onAddField, onDeleteField, onEditField, - onReorderField, limit = 1, isValidDropTarget, canDrop, @@ -59,17 +56,6 @@ const DropboxComponent = ({ }: DropboxProps) => { const prefersReducedMotion = usePrefersReducedMotion(); const [closing, setClosing] = useState(false); - const handleDragEnd = useCallback( - ({ source, destination }: DropResult) => { - if (!destination) return; - - onReorderField({ - sourceAggId: fields[source.index].id, - destinationAggId: fields[destination.index].id, - }); - }, - [fields, onReorderField] - ); const animateDelete = useCallback( (id: string) => { @@ -86,71 +72,72 @@ const DropboxComponent = ({ ); return ( - - -
- - {fields.map(({ id, label }, index) => ( - - - onEditField(id)}> - - {label} - - - animateDelete(id)} - data-test-subj="dropBoxRemoveBtn" - /> - - - ))} - - {fields.length < limit && ( - +
+ + {fields.map(({ id, label }, index) => ( + - - {i18n.translate('visBuilder.dropbox.addField.title', { - defaultMessage: 'Click or drop to add', - })} - - onAddField()} - data-test-subj="dropBoxAddBtn" - /> - - )} -
- - + + onEditField(id)}> + + {label} + + + animateDelete(id)} + data-test-subj="dropBoxRemoveBtn" + /> + + + ))} + + {fields.length < limit && ( + + + {i18n.translate('visBuilder.dropbox.addField.title', { + defaultMessage: 'Click or drop to add', + })} + + onAddField()} + data-test-subj="dropBoxAddBtn" + /> + + )} +
+
); }; const Dropbox = React.memo((dropBox: UseDropboxProps) => { const props = useDropbox(dropBox); - return ; }); 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 index 6aed9deb159e..d65608c97454 100644 --- 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 @@ -9,6 +9,7 @@ import { render, screen } from '@testing-library/react'; import { IndexPatternField } from '../../../../../data/public'; import { DraggableFieldButton } from './field'; +import { DropResult, EuiDragDropContext, EuiDroppable } from '@elastic/eui'; describe('visBuilder field', function () { describe('DraggableFieldButton', () => { @@ -28,7 +29,13 @@ describe('visBuilder field', function () { 'bytes' ), }; - render(); + render( + {}}> + + + + + ); const button = screen.getByTestId('field-bytes-showDetails'); 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 index ee34b4c92a37..92ce4a688c54 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/field.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/field.tsx @@ -29,7 +29,7 @@ */ import React, { useState } from 'react'; -import { EuiPopover } from '@elastic/eui'; +import { EuiDraggable, EuiPopover } from '@elastic/eui'; import { IndexPatternField } from '../../../../../data/public'; import { @@ -46,10 +46,11 @@ import './field.scss'; export interface FieldProps { field: IndexPatternField; getDetails: (field) => FieldDetails; + id: number; } // 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) => { +export const Field = ({ field, getDetails, id }: FieldProps) => { const [infoIsOpen, setOpen] = useState(false); function togglePopover() { @@ -60,7 +61,14 @@ export const Field = ({ field, getDetails }: FieldProps) => { } + button={ + + } isOpen={infoIsOpen} closePopover={() => setOpen(false)} anchorPosition="rightUp" @@ -78,9 +86,15 @@ export const Field = ({ field, getDetails }: FieldProps) => { export interface DraggableFieldButtonProps extends Partial { dragValue?: IndexPatternField['name'] | null | typeof COUNT_FIELD; field: Partial & Pick; + index: number; } -export const DraggableFieldButton = ({ dragValue, field, ...rest }: DraggableFieldButtonProps) => { +export const DraggableFieldButton = ({ + dragValue, + field, + index, + ...rest +}: DraggableFieldButtonProps) => { const { name, displayName, type, scripted = false } = field; const [dragProps] = useDrag({ namespace: 'field-data', @@ -110,5 +124,14 @@ export const DraggableFieldButton = ({ dragValue, field, ...rest }: DraggableFie onClick: () => {}, }; - return ; + return ( + + + + ); }; diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_selector.scss b/src/plugins/vis_builder/public/application/components/data_tab/field_selector.scss index 88cca98db86e..4bf1c21f006e 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/field_selector.scss +++ b/src/plugins/vis_builder/public/application/components/data_tab/field_selector.scss @@ -10,8 +10,6 @@ padding: $euiSizeS; &__fieldGroups { - @include euiYScrollWithShadows; - overflow-y: auto; margin-right: -$euiSizeS; padding-right: $euiSizeS; 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 index 980cfb50c666..d86e022d0cc3 100644 --- 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 @@ -7,6 +7,7 @@ import React from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import { FilterManager, IndexPatternField } from '../../../../../data/public'; import { FieldGroup } from './field_selector'; +import { DropResult, EuiDragDropContext, EuiDroppable } from '@elastic/eui'; const mockUseIndexPatterns = jest.fn(() => ({ selected: 'mockIndexPattern' })); const mockUseOnAddFilter = jest.fn(); @@ -68,7 +69,13 @@ describe('visBuilder sidebar field selector', function () { ...defaultProps, fields: ['bytes', 'machine.ram', 'memory', 'phpmemory'].map(getFields), }; - const { container } = render(); + const { container } = render( + {}}> + + + + + ); expect(container).toHaveTextContent(props.header); expect(container).toHaveTextContent(props.fields.length.toString()); 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 5c82419d5531..3d6a1120b502 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 @@ -4,7 +4,7 @@ */ import React, { useState, useEffect, useCallback, useMemo } from 'react'; -import { EuiFlexItem, EuiAccordion, EuiNotificationBadge, EuiTitle } from '@elastic/eui'; +import { EuiFlexItem, EuiDroppable } from '@elastic/eui'; import { IndexPattern, IndexPatternField, OSD_FIELD_TYPES } from '../../../../../data/public'; @@ -16,6 +16,8 @@ import { Field, DraggableFieldButton } from './field'; import { FieldDetails } from './types'; import { getAvailableFields, getDetails } from './utils'; import './field_selector.scss'; +import { DraggableAccordion } from '../draggable_accordion'; +import { FIELD_SELECTOR_ID } from './constants'; interface IFieldCategories { categorical: IndexPatternField[]; @@ -75,30 +77,59 @@ export const FieldSelector = () => {
{/* Count Field */} - - - - + + + + + + + + + + + +
); @@ -113,27 +144,14 @@ interface FieldGroupProps { export const FieldGroup = ({ fields, header, id, getDetailsByField }: FieldGroupProps) => { return ( - - {header} - - } - extraAction={ - - {fields?.length || 0} - - } - initialIsOpen - > - {fields?.map((field, i) => ( - - + ( + + ))} - + /> ); }; diff --git a/src/plugins/vis_builder/public/application/components/data_tab/index.tsx b/src/plugins/vis_builder/public/application/components/data_tab/index.tsx index 5f71e38141d3..8c79f680cb02 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/index.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/index.tsx @@ -3,19 +3,148 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import { DropResult, EuiDragDropContext } from '@elastic/eui'; import { FieldSelector } from './field_selector'; import './index.scss'; import { ConfigPanel } from './config_panel'; +import { useAggs, useVisualizationType } from '../../utils/use'; +import { useTypedDispatch, useTypedSelector } from '../../utils/state_management'; + +import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; +import { VisBuilderServices } from '../../../types'; +import { DropboxDisplay } from './dropbox'; +import { FIELD_SELECTOR_ID } from './constants'; +import { addFieldToConfiguration } from './drag_drop/add_field_to_configuration'; +import { replaceFieldInConfiguration } from './drag_drop/replace_field_in_configuration'; +import { reorderFieldsWithinSchema } from './drag_drop/reorder_fields_within_schema'; +import { moveFieldBetweenSchemas } from './drag_drop/move_field_between_schemas'; export const DATA_TAB_ID = 'data_tab'; +export interface SchemaDisplayStates { + [key: string]: DropboxDisplay[]; +} + export const DataTab = () => { + // Config panel States + const vizType = useVisualizationType(); + const editingState = useTypedSelector( + (state) => state.visualization.activeVisualization?.draftAgg + ); + const schemas = vizType.ui.containerConfig.data.schemas; + const { + services: { + data: { + search: { aggs: aggService }, + }, + }, + } = useOpenSearchDashboards(); + + const aggProps = useAggs(); + const [activeSchemaFields, setActiveSchemaFields] = useState(() => { + return schemas.all.reduce((acc, schema) => { + acc[schema.name] = []; + return acc; + }, {}); + }); + const dispatch = useTypedDispatch(); + + useEffect(() => { + const newState = schemas.all.reduce((acc, schema) => { + acc[schema.name] = []; + return acc; + }, {}); + const updatedState = { ...newState, ...activeSchemaFields }; + setActiveSchemaFields(updatedState); + // This useEffect hook should run whenever the upstream params corresponding to schemas and vizType changes hence disabling the eslint which asks to include activeSchemaFields as dependency + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [schemas, vizType]); + + const handleDragEnd = (dropResult: DropResult) => { + try { + const { source, destination, combine } = dropResult; + + const destinationSchemaName = destination?.droppableId || combine?.droppableId; + const sourceSchemaName = source.droppableId; + + if (!sourceSchemaName || !destinationSchemaName) { + // Invalid operation should contain a source and destination + return; + } + + const panelGroups = Array.from(schemas.all.map((schema) => schema.name)); + + if (Object.values(FIELD_SELECTOR_ID).includes(sourceSchemaName as FIELD_SELECTOR_ID)) { + if (panelGroups.includes(destinationSchemaName) && !combine) { + addFieldToConfiguration({ + dropResult, + aggProps, + aggService, + activeSchemaFields, + dispatch, + schemas, + }); + } else if (panelGroups.includes(destinationSchemaName) && combine) { + replaceFieldInConfiguration({ + dropResult, + aggProps, + aggService, + activeSchemaFields, + dispatch, + schemas, + }); + } + } else if (panelGroups.includes(sourceSchemaName)) { + if (panelGroups.includes(destinationSchemaName)) { + if (sourceSchemaName === destinationSchemaName && !combine) { + reorderFieldsWithinSchema({ + dropResult, + aggProps, + aggService, + activeSchemaFields, + dispatch, + schemas, + }); + } else if (sourceSchemaName !== destinationSchemaName && !combine) { + moveFieldBetweenSchemas({ + dropResult, + aggProps, + aggService, + activeSchemaFields, + dispatch, + schemas, + }); + } else if (combine) { + replaceFieldInConfiguration({ + dropResult, + aggProps, + aggService, + activeSchemaFields, + dispatch, + schemas, + }); + } + } + } + } catch (err) { + return; + } + }; + return ( -
- - -
+ +
+ + +
+
); }; diff --git a/src/plugins/vis_builder/public/application/components/data_tab/schema_to_dropbox.tsx b/src/plugins/vis_builder/public/application/components/data_tab/schema_to_dropbox.tsx index 518a6ae7af2f..390e7fb47638 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/schema_to_dropbox.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/schema_to_dropbox.tsx @@ -2,15 +2,31 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ - import React from 'react'; import { Schemas } from '../../../../../vis_default_editor/public'; import { Dropbox } from './dropbox'; import { Title } from './title'; +import { AggProps } from './config_panel'; +import { SchemaDisplayStates } from '.'; -export const mapSchemaToAggPanel = (schemas: Schemas) => { +export const mapSchemaToAggPanel = ( + schemas: Schemas, + aggProps: AggProps, + activeSchemaFields: SchemaDisplayStates, + setActiveSchemaFields: React.Dispatch> +) => { const panelComponents = schemas.all.map((schema) => { - return ; + return ( + + ); }); return ( diff --git a/src/plugins/vis_builder/public/application/components/data_tab/use/use_dropbox.tsx b/src/plugins/vis_builder/public/application/components/data_tab/use/use_dropbox.tsx index c41e4bc08662..d2d1be215785 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/use/use_dropbox.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/use/use_dropbox.tsx @@ -5,7 +5,6 @@ import { useState, useEffect, useCallback, useMemo } from 'react'; import { cloneDeep } from 'lodash'; -import { BucketAggType, IndexPatternField, propFilter } from '../../../../../../data/common'; import { Schema } from '../../../../../../vis_default_editor/public'; import { COUNT_FIELD, FieldDragDataType } from '../../../utils/drag_drop/types'; import { useTypedDispatch } from '../../../utils/state_management'; @@ -18,19 +17,30 @@ import { } from '../../../utils/state_management/visualization_slice'; import { useOpenSearchDashboards } from '../../../../../../opensearch_dashboards_react/public'; import { VisBuilderServices } from '../../../../types'; -import { useAggs } from '../../../utils/use'; - -const filterByName = propFilter('name'); -const filterByType = propFilter('type'); +import { getValidAggTypes } from '../utils/get_valid_aggregations'; +import { AggProps } from '../config_panel'; +import { SchemaDisplayStates } from '..'; export interface UseDropboxProps extends Pick { schema: Schema; + aggProps: AggProps; + activeSchemaFields: SchemaDisplayStates; + setActiveSchemaFields: React.Dispatch>; } export const useDropbox = (props: UseDropboxProps): DropboxProps => { - const { id: dropboxId, label, schema } = props; + const { + id: dropboxId, + label, + schema, + aggProps, + activeSchemaFields, + setActiveSchemaFields, + } = props; const [validAggTypes, setValidAggTypes] = useState([]); - const { aggConfigs, indexPattern, aggs, timeRange } = useAggs(); + const { aggConfigs, indexPattern, aggs, timeRange } = aggProps; + const fields = activeSchemaFields[schema.name]; + const dispatch = useTypedDispatch(); const { services: { @@ -60,6 +70,16 @@ export const useDropbox = (props: UseDropboxProps): DropboxProps => { [dropboxAggs, timeRange] ); + useEffect(() => { + if (displayFields && JSON.stringify(fields) !== JSON.stringify(displayFields)) { + const newDisplayState = { ...activeSchemaFields }; + newDisplayState[schema.name] = displayFields; + setActiveSchemaFields(newDisplayState); + } + // useEffect runs whenever disaplyFields changes and this in turn updates the activeSchema fields passed by parent hence disabling eslint that asks activeSchema to be included in dependecy list + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [displayFields]); + // Event handlers for each dropbox action type const onAddField = useCallback(() => { if (!aggConfigs || !indexPattern) { @@ -105,7 +125,6 @@ export const useDropbox = (props: UseDropboxProps): DropboxProps => { const onDeleteField = useCallback( (aggId: string) => { const newAggs = aggConfigs?.aggs.filter((agg) => agg.id !== aggId); - if (newAggs) { dispatch(updateAggConfigParams(newAggs.map((agg) => agg.serialize()))); } @@ -156,43 +175,25 @@ export const useDropbox = (props: UseDropboxProps): DropboxProps => { ); useEffect(() => { - const getValidAggTypes = () => { - if (!dragData || schema.group === 'none') return []; - const isCountField = dragData === COUNT_FIELD; - - const indexField = isCountField - ? { type: 'count' } - : getIndexPatternField(dragData, indexPattern?.fields ?? []); - - if (!indexField) return []; - - // Get all aggTypes allowed by the schema and get a list of all the aggTypes that the dragged index field can use - const aggTypes = aggService.types.getAll(); - // `types` can be either a Bucket or Metric aggType, but both types have the name property. - const allowedAggTypes = filterByName( - aggTypes[schema.group] as BucketAggType[], - schema.aggFilter - ); - - return ( - allowedAggTypes - .filter((aggType) => { - const allowedFieldTypes = aggType.paramByName('field')?.filterFieldTypes; - return filterByType([indexField], allowedFieldTypes).length !== 0; - }) - .filter((aggType) => (isCountField ? true : aggType.name !== 'count')) - // `types` can be either a Bucket or Metric aggType, but both types have the name property. - .map((aggType) => (aggType as BucketAggType).name) - ); - }; - - setValidAggTypes(getValidAggTypes()); + const fieldName = typeof dragData === typeof COUNT_FIELD ? '' : (dragData as string); + const sourceGroup = typeof dragData === typeof COUNT_FIELD ? 'preDefinedCountMetric' : ''; + + setValidAggTypes( + getValidAggTypes({ + fieldName, + sourceGroup, + destinationSchema: schema, + aggProps, + aggService, + sourceAgg: null, + }) + ); return () => { setValidAggTypes([]); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [aggService.types, dragData, indexPattern?.fields, schema.aggFilter, schema.group]); - const canDrop = validAggTypes.length > 0 && schema.max > dropboxAggs.length; return { @@ -210,6 +211,3 @@ export const useDropbox = (props: UseDropboxProps): DropboxProps => { dropProps, }; }; - -const getIndexPatternField = (indexFieldName: string, availableFields: IndexPatternField[]) => - availableFields.find(({ name }) => name === indexFieldName); diff --git a/src/plugins/vis_builder/public/application/components/data_tab/utils/get_valid_aggregations.tsx b/src/plugins/vis_builder/public/application/components/data_tab/utils/get_valid_aggregations.tsx new file mode 100644 index 000000000000..e88c3099a000 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/utils/get_valid_aggregations.tsx @@ -0,0 +1,99 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + AggConfig, + AggsStart, + BucketAggType, + IndexPatternField, + propFilter, +} from '../../../../../../data/common'; +import { Schema } from '../../../../../../vis_default_editor/public'; +import { AggProps } from '../config_panel'; + +export interface CreateNewAggConfig { + fieldName: string; + sourceGroup: string; + destinationSchema: Schema; + aggProps: AggProps; + aggService: AggsStart; + sourceAgg: AggConfig | null | undefined; +} + +const filterByName = propFilter('name'); +const filterByType = propFilter('type'); + +const getIndexPatternField = (indexFieldName: string, availableFields: IndexPatternField[]) => + availableFields.find(({ name }) => name === indexFieldName); + +export const getValidAggTypes = ({ + fieldName, + sourceGroup, + destinationSchema, + aggProps, + aggService, + sourceAgg, +}: CreateNewAggConfig) => { + const isCountField = + sourceGroup === 'preDefinedCountMetric' || + (sourceAgg && Object.keys(sourceAgg.params).length === 0); + + const indexField = isCountField + ? { type: 'count' } + : getIndexPatternField(fieldName, aggProps.indexPattern?.fields ?? []); + + if (!indexField) return []; + + // Get all aggTypes allowed by the schema and get a list of all the aggTypes that the dragged index field can use + const aggTypes = aggService.types.getAll(); + // `types` can be either a Bucket or Metric aggType, but both types have the name property. + const allowedAggTypes = filterByName( + aggTypes[destinationSchema.group] as BucketAggType[], + destinationSchema.aggFilter + ); + + return ( + allowedAggTypes + .filter((aggType) => { + const allowedFieldTypes = aggType.paramByName('field')?.filterFieldTypes; + return filterByType([indexField], allowedFieldTypes).length !== 0; + }) + .filter((aggType) => (isCountField ? true : aggType.name !== 'count')) + // `types` can be either a Bucket or Metric aggType, but both types have the name property. + .map((aggType) => (aggType as BucketAggType).name) + ); +}; + +export const createNewAggConfig = ({ + fieldName, + sourceGroup, + destinationSchema, + aggProps, + aggService, + sourceAgg, +}: CreateNewAggConfig) => { + const schemaAggTypes = (destinationSchema.defaults as any).aggTypes; + + const destinationValidAggType = getValidAggTypes({ + fieldName, + sourceGroup, + destinationSchema, + aggProps, + aggService, + sourceAgg, + }); + + const allowedAggTypes = schemaAggTypes + ? schemaAggTypes.filter((type: string) => destinationValidAggType.includes(type)) + : []; + + aggProps.aggConfigs?.createAggConfig({ + type: allowedAggTypes[0] || destinationValidAggType[0], + schema: destinationSchema.name, + params: { + field: fieldName, + }, + }); +}; diff --git a/src/plugins/vis_builder/public/application/components/draggable_accordion.scss b/src/plugins/vis_builder/public/application/components/draggable_accordion.scss new file mode 100644 index 000000000000..3bfcac218d9c --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/draggable_accordion.scss @@ -0,0 +1,34 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +.draggableAccordion__title { + display: inline-block; +} + +.draggableAccordion__button { + padding: $euiSizeS $euiSizeS $euiSizeS 0; + + &:hover { + text-decoration: none; + + .draggableAccordion__title { + text-decoration: underline; + } + } +} + +.draggableAccordion__badge { + justify-content: center; + align-items: center; +} + +.draggableAccordion { + border-top: $euiBorderThin; + border-bottom: $euiBorderThin; + + & + .draggableAccordion { + border-top: none; + } +} diff --git a/src/plugins/vis_builder/public/application/components/draggable_accordion.tsx b/src/plugins/vis_builder/public/application/components/draggable_accordion.tsx new file mode 100644 index 000000000000..99457800e7f7 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/draggable_accordion.tsx @@ -0,0 +1,59 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiNotificationBadge, + EuiTitle, +} from '@elastic/eui'; +import React from 'react'; +import { useState } from 'react'; +import './draggable_accordion.scss'; + +export const DraggableAccordion = ({ children, title, defaultState = true }) => { + const [isOpen, setIsOpen] = useState(defaultState); + + function handleOnClick() { + setIsOpen(!isOpen); + } + + return ( +
+ + + + + + {title} + + + + + + {children?.length || 0} + + + + + {isOpen && children} + + +
+ ); +}; From a0eea7d266092faff9a5a4f331802b4448b22602 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 13:23:04 -0700 Subject: [PATCH 100/276] Add Scripted Field Support in Vis Builder (#6974) (#7013) (cherry picked from commit e74ed2c5c27b8dcc5cd83a8f84e3113c210c3b80) Signed-off-by: Suchit Sahoo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../data_tab/utils/get_available_fields.test.ts | 17 ++++++++++++++++- .../data_tab/utils/get_available_fields.ts | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/plugins/vis_builder/public/application/components/data_tab/utils/get_available_fields.test.ts b/src/plugins/vis_builder/public/application/components/data_tab/utils/get_available_fields.test.ts index 60cb780245c7..9cf51b67d43c 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/utils/get_available_fields.test.ts +++ b/src/plugins/vis_builder/public/application/components/data_tab/utils/get_available_fields.test.ts @@ -44,7 +44,7 @@ describe('getAvailableFields', () => { }, ]); - expect(getAvailableFields(fields).length).toBe(1); + expect(getAvailableFields(fields).length).toBe(2); }); test('should return all fields if filterFieldTypes was not specified', () => { @@ -60,6 +60,21 @@ describe('getAvailableFields', () => { expect(getAvailableFields(fields).length).toBe(2); }); + test('should return scripted fields', () => { + const fields = createIndexFields([ + { + name: 'field 1', + scripted: true, + }, + { + name: 'field 2', + scripted: true, + }, + ]); + + expect(getAvailableFields(fields).length).toBe(2); + }); + test('should filterFieldTypes', () => { const fields = createIndexFields([ { diff --git a/src/plugins/vis_builder/public/application/components/data_tab/utils/get_available_fields.ts b/src/plugins/vis_builder/public/application/components/data_tab/utils/get_available_fields.ts index d938e92b6978..f6719f16ec2a 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/utils/get_available_fields.ts +++ b/src/plugins/vis_builder/public/application/components/data_tab/utils/get_available_fields.ts @@ -17,7 +17,7 @@ export const getAvailableFields = ( filterFieldTypes: FieldTypes = '*' ) => { const filteredFields = fields.filter((field: IndexPatternField) => { - if (!field.aggregatable || isNestedField(field) || field.scripted) { + if (!field.aggregatable || isNestedField(field)) { return false; } From e2bb1e4290372b559c56fb4f657693c0cee987b3 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:48:10 -0700 Subject: [PATCH 101/276] [Discover-next] add datasource container (#7157) (#7164) * [Discover-next] add datasource container Enables the editor to let plugins to mount their own data source component to the data source container. Issue partially resolved: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/7129 * Changeset file for PR #7157 created/updated --------- (cherry picked from commit e1c5cfd102e324198b871ebb5044d079e81ca3cd) Signed-off-by: Kawika Avilla Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7157.yml | 2 ++ .../public/ui/query_editor/_query_editor.scss | 16 ++++++++++ .../public/ui/query_editor/query_editor.tsx | 31 ++++++++++++++++--- .../ui/query_editor/query_editor_top_row.tsx | 4 ++- .../ui/search_bar/create_search_bar.tsx | 9 ++++++ .../data/public/ui/search_bar/search_bar.tsx | 2 ++ src/plugins/data/public/ui/types.ts | 4 ++- src/plugins/data/public/ui/ui_service.ts | 7 +++++ 8 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 changelogs/fragments/7157.yml diff --git a/changelogs/fragments/7157.yml b/changelogs/fragments/7157.yml new file mode 100644 index 000000000000..e7b25524e961 --- /dev/null +++ b/changelogs/fragments/7157.yml @@ -0,0 +1,2 @@ +feat: +- Query editor and dataframes datasources container ([#7157](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7157)) \ No newline at end of file diff --git a/src/plugins/data/public/ui/query_editor/_query_editor.scss b/src/plugins/data/public/ui/query_editor/_query_editor.scss index fafb85a1bea5..80ddd42fede5 100644 --- a/src/plugins/data/public/ui/query_editor/_query_editor.scss +++ b/src/plugins/data/public/ui/query_editor/_query_editor.scss @@ -24,6 +24,22 @@ } .osdQueryEditor__dataSourceWrapper { + .dataSourceSelect { + border-bottom: $euiBorderThin !important; + + :first-child { + box-shadow: none !important; + height: 100%; + border-radius: 0; + } + + div:is([class$="--group"]) { + padding: 0 !important; + } + } +} + +.osdQueryEditor__dataSetWrapper { .dataExplorerDSSelect { border-bottom: $euiBorderThin !important; diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index 0fe6aad3f8b4..19c4c527038c 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -25,6 +25,7 @@ export interface QueryEditorProps { indexPatterns: Array; dataSource?: DataSource; query: Query; + dataSourceContainerRef?: React.RefCallback; containerRef?: React.RefCallback; settings: Settings; disableAutoFocus?: boolean; @@ -54,6 +55,7 @@ interface Props extends QueryEditorProps { interface State { isDataSourcesVisible: boolean; + isDataSetsVisible: boolean; isSuggestionsVisible: boolean; index: number | null; suggestions: QuerySuggestion[]; @@ -77,7 +79,8 @@ const KEY_CODES = { // eslint-disable-next-line import/no-default-export export default class QueryEditorUI extends Component { public state: State = { - isDataSourcesVisible: true, + isDataSourcesVisible: false, + isDataSetsVisible: true, isSuggestionsVisible: false, index: null, suggestions: [], @@ -212,7 +215,10 @@ export default class QueryEditorUI extends Component { : undefined; this.onChange(newQuery, dateRange); this.onSubmit(newQuery, dateRange); - this.setState({ isDataSourcesVisible: enhancement?.searchBar?.showDataSourceSelector ?? true }); + this.setState({ isDataSetsVisible: enhancement?.searchBar?.showDataSetsSelector ?? true }); + this.setState({ + isDataSourcesVisible: enhancement?.searchBar?.showDataSourcesSelector ?? true, + }); }; private initPersistedLog = () => { @@ -227,10 +233,19 @@ export default class QueryEditorUI extends Component { const isDataSourcesVisible = this.props.settings.getQueryEnhancements(this.props.query.language)?.searchBar - ?.showDataSourceSelector ?? true; + ?.showDataSourcesSelector ?? true; this.setState({ isDataSourcesVisible }); }; + private initDataSetsVisibility = () => { + if (this.componentIsUnmounting) return; + + const isDataSetsVisible = + this.props.settings.getQueryEnhancements(this.props.query.language)?.searchBar + ?.showDataSetsSelector ?? true; + this.setState({ isDataSetsVisible }); + }; + public onMouseEnterSuggestion = (index: number) => { this.setState({ index }); }; @@ -246,6 +261,7 @@ export default class QueryEditorUI extends Component { this.initPersistedLog(); // this.fetchIndexPatterns().then(this.updateSuggestions); this.initDataSourcesVisibility(); + this.initDataSetsVisibility(); } public componentDidUpdate(prevProps: Props) { @@ -280,6 +296,11 @@ export default class QueryEditorUI extends Component { {this.props.prepend} + {this.state.isDataSourcesVisible && ( + +
+ + )} { appName={this.services.appName} /> - {this.state.isDataSourcesVisible && ( - + {this.state.isDataSetsVisible && ( +
)} diff --git a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx index be75c44ece60..3ea715418ab1 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx @@ -14,7 +14,7 @@ import { } from '@elastic/eui'; import classNames from 'classnames'; import { compact, isEqual } from 'lodash'; -import React, { useRef, useState } from 'react'; +import React, { useState } from 'react'; import { DataSource, IDataPluginServices, @@ -38,6 +38,7 @@ const QueryEditor = withOpenSearchDashboards(QueryEditorUI); // @internal export interface QueryEditorTopRowProps { query?: Query; + dataSourceContainerRef?: React.RefCallback; containerRef?: React.RefCallback; settings?: Settings; onSubmit: (payload: { dateRange: TimeRange; query?: Query }) => void; @@ -234,6 +235,7 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { dataSource={props.dataSource} prepend={props.prepend} query={parsedQuery} + dataSourceContainerRef={props.dataSourceContainerRef} containerRef={props.containerRef} settings={props.settings!} screenTitle={props.screenTitle} diff --git a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx index 9baeab489d4b..244f4296216c 100644 --- a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx @@ -48,6 +48,7 @@ interface StatefulSearchBarDeps { data: Omit; storage: IStorageWrapper; settings: Settings; + setDataSourceContainerRef: (ref: HTMLDivElement | null) => void; setContainerRef: (ref: HTMLDivElement | null) => void; } @@ -138,6 +139,7 @@ export function createSearchBar({ storage, data, settings, + setDataSourceContainerRef, setContainerRef, }: StatefulSearchBarDeps) { // App name should come from the core application service. @@ -174,6 +176,12 @@ export function createSearchBar({ notifications: core.notifications, }); + const dataSourceContainerRef = useCallback((node) => { + if (node) { + setDataSourceContainerRef(node); + } + }, []); + const containerRef = useCallback((node) => { if (node) { setContainerRef(node); @@ -220,6 +228,7 @@ export function createSearchBar({ filters={filters} query={query} settings={settings} + dataSourceContainerRef={dataSourceContainerRef} containerRef={containerRef} onFiltersUpdated={defaultFiltersUpdated(data.query)} onRefreshChange={defaultOnRefreshChange(data.query)} diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index 54e39fcb0b8d..11914f134443 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -80,6 +80,7 @@ export interface SearchBarOwnProps { // Query bar - should be in SearchBarInjectedDeps query?: Query; settings?: Settings; + dataSourceContainerRef?: React.RefCallback; containerRef?: React.RefCallback; // Show when user has privileges to save showSaveQuery?: boolean; @@ -490,6 +491,7 @@ class SearchBarUI extends Component { queryEditor = ( ; searchBar?: { - showDataSourceSelector?: boolean; + showDataSetsSelector?: boolean; + showDataSourcesSelector?: boolean; showQueryInput?: boolean; showFilterBar?: boolean; showDatePicker?: boolean; @@ -66,5 +67,6 @@ export interface IUiStart { SearchBar: React.ComponentType; SuggestionsComponent: React.ComponentType; Settings: Settings; + dataSourceContainer$: Observable; container$: Observable; } diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index e2dcae737acc..243490dc8201 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -29,6 +29,7 @@ export class UiService implements Plugin { enhancementsConfig: ConfigSchema['enhancements']; private queryEnhancements: Map = new Map(); private queryEditorExtensionMap: Record = {}; + private dataSourceContainer$ = new BehaviorSubject(null); private container$ = new BehaviorSubject(null); constructor(initializerContext: PluginInitializerContext) { @@ -62,6 +63,10 @@ export class UiService implements Plugin { queryEditorExtensionMap: this.queryEditorExtensionMap, }); + const setDataSourceContainerRef = (ref: HTMLDivElement | null) => { + this.dataSourceContainer$.next(ref); + }; + const setContainerRef = (ref: HTMLDivElement | null) => { this.container$.next(ref); }; @@ -71,6 +76,7 @@ export class UiService implements Plugin { data: dataServices, storage, settings: Settings, + setDataSourceContainerRef, setContainerRef, }); @@ -79,6 +85,7 @@ export class UiService implements Plugin { SearchBar, SuggestionsComponent, Settings, + dataSourceContainer$: this.dataSourceContainer$, container$: this.container$, }; } From 450ec4b70ee52dd0b8afde41dcb861fba4fede10 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:50:37 -0700 Subject: [PATCH 102/276] [Discover-next] (QueryEditorExtensions) change isEnabled to an observable (#7183) (#7193) * (QueryEditorExtensions) change isEnabled to an observable * rename search bar extension to query editor extension in comments * Changeset file for PR #7183 created/updated --------- (cherry picked from commit 774f64ed887f8a86af10423bb66b5128dd14c40e) Signed-off-by: Joshua Li Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7183.yml | 2 ++ .../query_editor_extension.test.tsx | 7 ++++--- .../query_editor_extension.tsx | 18 ++++++++++-------- 3 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 changelogs/fragments/7183.yml diff --git a/changelogs/fragments/7183.yml b/changelogs/fragments/7183.yml new file mode 100644 index 000000000000..f3fc5235226d --- /dev/null +++ b/changelogs/fragments/7183.yml @@ -0,0 +1,2 @@ +feat: +- [QueryEditorExtensions] change `isEnabled` to an observable ([#7183](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7183)) \ No newline at end of file diff --git a/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.test.tsx b/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.test.tsx index b3c8747e833d..6ff348fbf3bd 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.test.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.test.tsx @@ -5,6 +5,7 @@ import { render, waitFor } from '@testing-library/react'; import React, { ComponentProps } from 'react'; +import { of } from 'rxjs'; import { IIndexPattern } from '../../../../common'; import { QueryEditorExtension } from './query_editor_extension'; @@ -39,7 +40,7 @@ describe('QueryEditorExtension', () => { config: { id: 'test-extension', order: 1, - isEnabled: isEnabledMock, + isEnabled$: isEnabledMock, getComponent: getComponentMock, getBanner: getBannerMock, }, @@ -56,7 +57,7 @@ describe('QueryEditorExtension', () => { }); it('renders correctly when isEnabled is true', async () => { - isEnabledMock.mockResolvedValue(true); + isEnabledMock.mockReturnValue(of(true)); getComponentMock.mockReturnValue(
Test Component
); getBannerMock.mockReturnValue(
Test Banner
); @@ -72,7 +73,7 @@ describe('QueryEditorExtension', () => { }); it('does not render when isEnabled is false', async () => { - isEnabledMock.mockResolvedValue(false); + isEnabledMock.mockReturnValue(of(false)); getComponentMock.mockReturnValue(
Test Component
); const { queryByText } = render(); diff --git a/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.tsx b/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.tsx index 30b02f0f15dc..f684aebea1d9 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.tsx @@ -6,6 +6,7 @@ import { EuiErrorBoundary } from '@elastic/eui'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import ReactDOM from 'react-dom'; +import { Observable } from 'rxjs'; import { IIndexPattern } from '../../../../common'; import { DataSource } from '../../../data_sources/datasource'; @@ -33,7 +34,7 @@ export interface QueryEditorExtensionDependencies { export interface QueryEditorExtensionConfig { /** - * The id for the search bar extension. + * The id for the query editor extension. */ id: string; /** @@ -41,22 +42,22 @@ export interface QueryEditorExtensionConfig { */ order: number; /** - * A function that determines if the search bar extension is enabled and should be rendered on UI. + * A function that determines if the query editor extension is enabled and should be rendered on UI. * @returns whether the extension is enabled. */ - isEnabled: (dependencies: QueryEditorExtensionDependencies) => Promise; + isEnabled$: (dependencies: QueryEditorExtensionDependencies) => Observable; /** - * A function that returns the search bar extension component. The component + * A function that returns the query editor extension component. The component * will be displayed on top of the query editor in the search bar. * @param dependencies - The dependencies required for the extension. - * @returns The component the search bar extension. + * @returns The component the query editor extension. */ getComponent?: (dependencies: QueryEditorExtensionDependencies) => React.ReactElement | null; /** - * A function that returns the search bar extension banner. The banner is a + * A function that returns the query editor extension banner. The banner is a * component that will be displayed on top of the search bar. * @param dependencies - The dependencies required for the extension. - * @returns The component the search bar extension. + * @returns The component the query editor extension. */ getBanner?: (dependencies: QueryEditorExtensionDependencies) => React.ReactElement | null; } @@ -92,9 +93,10 @@ export const QueryEditorExtension: React.FC = (props) }, []); useEffect(() => { - props.config.isEnabled(props.dependencies).then((enabled) => { + const subscription = props.config.isEnabled$(props.dependencies).subscribe((enabled) => { if (isMounted.current) setIsEnabled(enabled); }); + return () => subscription.unsubscribe(); }, [props.dependencies, props.config]); if (!isEnabled) return null; From 6685bce770af11e40394f99ff78ddf0392219d4d Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 07:00:17 +0800 Subject: [PATCH 103/276] [HomePage] Add home page static list card (#7351) (#7355) * feat: add home static list card * Changeset file for PR #7351 created/updated * update link property * add i18n and description --------- (cherry picked from commit e64de155546d584b92c868c38c6084d1d04b281e) Signed-off-by: tygao Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7351.yml | 2 + .../home_list_card.test.tsx.snap | 51 +++++++++ .../components/home_list_card.test.tsx | 27 +++++ .../application/components/home_list_card.tsx | 102 ++++++++++++++++++ .../home/public/application/home_render.tsx | 36 ++++++- 5 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/7351.yml create mode 100644 src/plugins/home/public/application/components/__snapshots__/home_list_card.test.tsx.snap create mode 100644 src/plugins/home/public/application/components/home_list_card.test.tsx create mode 100644 src/plugins/home/public/application/components/home_list_card.tsx diff --git a/changelogs/fragments/7351.yml b/changelogs/fragments/7351.yml new file mode 100644 index 000000000000..e8cbdc921c78 --- /dev/null +++ b/changelogs/fragments/7351.yml @@ -0,0 +1,2 @@ +feat: +- Add home page static list card ([#7351](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7351)) \ No newline at end of file diff --git a/src/plugins/home/public/application/components/__snapshots__/home_list_card.test.tsx.snap b/src/plugins/home/public/application/components/__snapshots__/home_list_card.test.tsx.snap new file mode 100644 index 000000000000..892d6a8dc225 --- /dev/null +++ b/src/plugins/home/public/application/components/__snapshots__/home_list_card.test.tsx.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` should render static content normally 1`] = ` + +
+
+

+ What's New +

+
+
+
+ + Quickstart guide + + + (opens in a new tab or window) + + +
+
+ Get started in minutes with OpenSearch Dashboards +
+
+
+
+ +`; diff --git a/src/plugins/home/public/application/components/home_list_card.test.tsx b/src/plugins/home/public/application/components/home_list_card.test.tsx new file mode 100644 index 000000000000..3e0a646e7279 --- /dev/null +++ b/src/plugins/home/public/application/components/home_list_card.test.tsx @@ -0,0 +1,27 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; + +import { HomeListCard } from './home_list_card'; + +describe('', () => { + it('should render static content normally', async () => { + const mockConfig = { + title: `What's New`, + list: [ + { + label: 'Quickstart guide', + href: 'https://opensearch.org/docs/latest/dashboards/quickstart/', + target: '_blank', + description: 'Get started in minutes with OpenSearch Dashboards', + }, + ], + }; + const { baseElement } = render(); + expect(baseElement).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/home/public/application/components/home_list_card.tsx b/src/plugins/home/public/application/components/home_list_card.tsx new file mode 100644 index 000000000000..c905ca3272cc --- /dev/null +++ b/src/plugins/home/public/application/components/home_list_card.tsx @@ -0,0 +1,102 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { + EuiDescriptionList, + EuiText, + EuiLink, + EuiTitle, + EuiPanel, + EuiDescriptionListTitle, + EuiDescriptionListDescription, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; + +export const LEARN_OPENSEARCH_CONFIG = { + title: i18n.translate('homepage.card.learnOpenSearch.title', { + defaultMessage: 'Learn Opensearch', + }), + list: [ + { + label: 'Quickstart guide', + href: 'https://opensearch.org/docs/latest/dashboards/quickstart/', + description: 'Get started in minutes with OpenSearch Dashboards', + }, + { + label: 'Building data visualizations', + href: 'https://opensearch.org/docs/latest/dashboards/visualize/viz-index/', + description: 'Design interactive charts and graphs to unlock insights form your data.', + }, + { + label: 'Creating dashboards', + href: 'https://opensearch.org/docs/latest/dashboards/dashboard/index/', + description: 'Build interactive dashboards to explore and analyze your data', + }, + ], + allLink: 'https://opensearch.org/docs/latest/', +}; + +export const WHATS_NEW_CONFIG = { + title: i18n.translate('homepage.card.whatsNew.title', { + defaultMessage: `What's New`, + }), + list: [ + { + label: 'Quickstart guide', + href: 'https://opensearch.org/docs/latest/dashboards/quickstart/', + description: 'Get started in minutes with OpenSearch Dashboards', + }, + ], +}; + +interface Config { + title: string; + list: Array<{ + label: string; + href: string; + description: string; + }>; + allLink?: string; +} + +export const HomeListCard = ({ config }: { config: Config }) => { + return ( + <> + + +

{config.title}

+
+ + {config.list.length > 0 && ( + + {config.list.map((item) => ( + <> + + + {item.label} + + + {item.description} + + ))} + + )} + + {config.allLink ? ( + <> + + + + View all + + + + ) : null} +
+ + ); +}; diff --git a/src/plugins/home/public/application/home_render.tsx b/src/plugins/home/public/application/home_render.tsx index 86292469cc7a..5d0497b7c39e 100644 --- a/src/plugins/home/public/application/home_render.tsx +++ b/src/plugins/home/public/application/home_render.tsx @@ -9,7 +9,12 @@ import { ContentManagementPluginSetup, ContentManagementPluginStart, } from '../../../../plugins/content_management/public'; -import { HOME_PAGE_ID, SECTIONS } from '../../common/constants'; +import { HOME_PAGE_ID, SECTIONS, HOME_CONTENT_AREAS } from '../../common/constants'; +import { + WHATS_NEW_CONFIG, + LEARN_OPENSEARCH_CONFIG, + HomeListCard, +} from './components/home_list_card'; export const setupHome = (contentManagement: ContentManagementPluginSetup) => { contentManagement.registerPage({ @@ -50,4 +55,31 @@ export const setupHome = (contentManagement: ContentManagementPluginSetup) => { }); }; -export const initHome = (contentManagement: ContentManagementPluginStart, core: CoreStart) => {}; +export const initHome = (contentManagement: ContentManagementPluginStart, core: CoreStart) => { + contentManagement.registerContentProvider({ + id: 'whats_new_cards', + getContent: () => ({ + id: 'whats_new', + kind: 'custom', + order: 3, + render: () => + React.createElement(HomeListCard, { + config: WHATS_NEW_CONFIG, + }), + }), + getTargetArea: () => HOME_CONTENT_AREAS.SERVICE_CARDS, + }); + contentManagement.registerContentProvider({ + id: 'learn_opensearch_new_cards', + getContent: () => ({ + id: 'learn_opensearch', + kind: 'custom', + order: 4, + render: () => + React.createElement(HomeListCard, { + config: LEARN_OPENSEARCH_CONFIG, + }), + }), + getTargetArea: () => HOME_CONTENT_AREAS.SERVICE_CARDS, + }); +}; From 69d913de0d2a4c114d7adaded62ddde1e255d440 Mon Sep 17 00:00:00 2001 From: Dan Dong <58446449+danieldong51@users.noreply.github.com> Date: Mon, 22 Jul 2024 16:16:14 -0700 Subject: [PATCH 104/276] Applied missing guidance for visBuilder (#7373) Signed-off-by: Dan Dong --- changelogs/fragments/7341.yml | 2 + .../apply_filter_popover_content.tsx | 13 +++-- .../components/data_tab/field_bucket.test.tsx | 58 +++++++++++++++++++ .../components/data_tab/field_bucket.tsx | 46 ++++++++++----- .../components/data_tab/field_details.tsx | 2 +- .../public/components/sidebar/controls.tsx | 2 +- 6 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 changelogs/fragments/7341.yml create mode 100644 src/plugins/vis_builder/public/application/components/data_tab/field_bucket.test.tsx diff --git a/changelogs/fragments/7341.yml b/changelogs/fragments/7341.yml new file mode 100644 index 000000000000..bae56254beb3 --- /dev/null +++ b/changelogs/fragments/7341.yml @@ -0,0 +1,2 @@ +refactor: +- [Look&Feel] Apply guidance for visBuilder ([#7341](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7341)) \ No newline at end of file diff --git a/src/plugins/data/public/ui/apply_filters/apply_filter_popover_content.tsx b/src/plugins/data/public/ui/apply_filters/apply_filter_popover_content.tsx index f6633b56740d..3565d7f4cd96 100644 --- a/src/plugins/data/public/ui/apply_filters/apply_filter_popover_content.tsx +++ b/src/plugins/data/public/ui/apply_filters/apply_filter_popover_content.tsx @@ -38,6 +38,7 @@ import { EuiModalHeader, EuiModalHeaderTitle, EuiSwitch, + EuiText, } from '@elastic/eui'; import { FormattedMessage } from '@osd/i18n/react'; import React, { Component } from 'react'; @@ -100,10 +101,14 @@ export default class ApplyFiltersPopoverContent extends Component - + +

+ +

+
diff --git a/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.test.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.test.tsx new file mode 100644 index 000000000000..a8daa0cbb139 --- /dev/null +++ b/src/plugins/vis_builder/public/application/components/data_tab/field_bucket.test.tsx @@ -0,0 +1,58 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +// @ts-ignore +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { IndexPatternField } from '../../../../../data/common'; +// @ts-ignore +import { findTestSubject } from '@elastic/eui/lib/test'; +import { FieldBucket } from './field_bucket'; +import { Bucket } from './types'; + +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 bucket', function () { + function mountComponent(field: IndexPatternField, bucket: Bucket) { + const compProps = { field, bucket }; + return mountWithIntl(); + } + + it('should render with buttons if field is filterable', async () => { + const field = new IndexPatternField( + { + name: 'bytes', + type: 'number', + esTypes: ['long'], + count: 10, + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + 'bytes' + ); + const bucket = { + display: `display`, + value: `value`, + percent: 25, + count: 100, + }; + const comp = mountComponent(field, bucket); + const addButton = findTestSubject(comp, 'plus-bytes-value'); + const minusButton = findTestSubject(comp, 'minus-bytes-value'); + expect(addButton.length).toBe(1); + expect(minusButton.length).toBe(1); + + addButton.simulate('click'); + minusButton.simulate('click'); + expect(mockUseOnAddFilter).toHaveBeenCalledTimes(2); + }); +}); 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 index 1a45857a6550..e724e5bf34b6 100644 --- 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 @@ -11,6 +11,7 @@ import { EuiFlexItem, EuiSpacer, EuiProgress, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; @@ -35,6 +36,9 @@ export function FieldBucket({ bucket, field }: FieldBucketProps) { // We need this to communicate to users when a top value is actually an empty string defaultMessage: 'Empty string', }); + const addText = i18n.translate('visBuilder.fieldSelector.detailsView.filterValueButtonToolTip', { + defaultMessage: 'Filter for value', + }); const addLabel = i18n.translate( 'visBuilder.fieldSelector.detailsView.filterValueButtonAriaLabel', { @@ -42,6 +46,12 @@ export function FieldBucket({ bucket, field }: FieldBucketProps) { values: { fieldName, value }, } ); + const removeText = i18n.translate( + 'visBuilder.fieldSelector.detailsView.filterOutValueButtonToolTip', + { + defaultMessage: 'Filter out value', + } + ); const removeLabel = i18n.translate( 'visBuilder.fieldSelector.detailsView.filterOutValueButtonAriaLabel', { @@ -84,22 +94,26 @@ export function FieldBucket({ bucket, field }: FieldBucketProps) { {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}`} - /> + + 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.tsx b/src/plugins/vis_builder/public/application/components/data_tab/field_details.tsx index cf6f4974bb18..36db438e7ff9 100644 --- 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 @@ -53,7 +53,7 @@ export function FieldDetailsView({ field, details }: FieldDetailsProps) { return ( <> - {title} + {title}
{error ? ( diff --git a/src/plugins/vis_default_editor/public/components/sidebar/controls.tsx b/src/plugins/vis_default_editor/public/components/sidebar/controls.tsx index ebdc45a730ee..46658ca77de0 100644 --- a/src/plugins/vis_default_editor/public/components/sidebar/controls.tsx +++ b/src/plugins/vis_default_editor/public/components/sidebar/controls.tsx @@ -109,7 +109,7 @@ function DefaultEditorControls({ data-test-subj="visualizeEditorRenderButton" disabled={!isDirty} fill - iconType="play" + iconType="refresh" onClick={applyChanges} size="s" > From 704f2fa29d9801c8ac45adc4db38dfaec65d66e9 Mon Sep 17 00:00:00 2001 From: Jialiang Liang Date: Mon, 22 Jul 2024 16:35:14 -0700 Subject: [PATCH 105/276] [Backport 2.x][MDS] Observability Datasource Plugin migration with MDS support for Data Connection Table (#7371) * [MDS] Observability Datasource Plugin migration with MDS support (#7143) * Observability Datasource Plugin migration with MDS support Signed-off-by: Ryan Liang * Switch to use doc services for doc links of configuration of s3 datasource Signed-off-by: Ryan Liang * Add tests for home panel Signed-off-by: Ryan Liang * Fix the snapshot for mds Signed-off-by: Ryan Liang * Add tests for data source creation panel Signed-off-by: Ryan Liang * Add tests for dq data connection table Signed-off-by: Ryan Liang * Add tests for dq configuration Signed-off-by: Ryan Liang * Add readonly for s3glue doc link Signed-off-by: Ryan Liang * Add tests for s3 prometheus creation and review Signed-off-by: Ryan Liang * Fix mount feature flag behavior and tests Signed-off-by: Ryan Liang * Shorten file names Signed-off-by: Ryan Liang * Shorten file names again Signed-off-by: Ryan Liang * Experiment 1 Signed-off-by: Ryan Liang * Fix the visbuilder failure 1 Signed-off-by: Ryan Liang * Fix the setter of datasource setup in vis_type_timeseries Signed-off-by: Ryan Liang * Synced branch Signed-off-by: Ryan Liang * Fix the readonly in doc link and add change log Signed-off-by: Ryan Liang * Fix the create opensearch datasource's cancel button redirection Signed-off-by: Ryan Liang * Add more test cases for breadscrumb changes and mount behavior based on the plugin registration Signed-off-by: Ryan Liang --------- Signed-off-by: Ryan Liang * [MDS] Fix the dsm plugin setup when mds feature flag is disabled (#7163) * Fix the dsm plugin setup when mds feature flag is disabled Signed-off-by: Ryan Liang * Changeset file for PR #7163 created/updated --------- Signed-off-by: Ryan Liang Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> * Changeset file for PR #7371 created/updated * Fix snapshots Signed-off-by: Ryan Liang --------- Signed-off-by: Ryan Liang Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7143.yml | 2 + changelogs/fragments/7163.yml | 2 + changelogs/fragments/7371.yml | 2 + .../public/doc_links/doc_links_service.ts | 3 + .../dashboard_listing.test.tsx.snap | 5 + .../dashboard_top_nav.test.tsx.snap | 6 + .../opensearch_dashboards.json | 4 +- .../public/components/breadcrumbs.test.ts | 30 +- .../public/components/breadcrumbs.ts | 44 + .../public/components/constants.tsx | 27 + .../create_data_source_wizard.test.tsx | 2 +- .../create_data_source_wizard.tsx | 6 +- ...create_data_source_card_view.test.tsx.snap | 85 + .../create_data_source_panel.test.tsx.snap | 25 + ...ate_data_source_panel_header.test.tsx.snap | 34 + .../create_data_source_card_view.test.tsx | 105 + .../create_data_source_card_view.tsx | 82 + .../create_data_source_description.tsx | 24 + .../create_data_source_panel.test.tsx | 64 + .../create_data_source_panel.tsx | 48 + .../create_data_source_panel_header.test.tsx | 35 + .../create_data_source_panel_header.tsx | 34 + .../data_source_home_panel.test.tsx.snap | 75 + .../data_source_page_header.test.tsx.snap | 34 + .../data_source_home_panel.test.tsx | 99 + .../data_source_home_panel.tsx | 111 + .../data_source_page_header.test.tsx | 41 + .../data_source_page_header.tsx | 37 + .../data_source_table.test.tsx.snap | 5190 ++++++----------- .../data_source_table/data_source_table.tsx | 134 +- ...ery_data_source_delete_modal.test.tsx.snap | 60 + ...query_data_connections_table.test.tsx.snap | 920 +++ ...ct_query_data_source_delete_modal.test.tsx | 76 + .../direct_query_data_source_delete_modal.tsx | 82 + ...rect_query_data_connections_table.test.tsx | 128 + ...ge_direct_query_data_connections_table.tsx | 283 + .../query_permissions.test.tsx.snap | 187 + ...figure_amazon_s3_data_source.test.tsx.snap | 1253 ++++ ...review_amazon_s3_data_source.test.tsx.snap | 398 ++ .../configure_amazon_s3_data_source.test.tsx | 183 + .../configure_amazon_s3_data_source.tsx | 234 + .../review_amazon_s3_data_source.test.tsx | 104 + .../review_amazon_s3_data_source.tsx | 120 + ...nfigure_direct_query_data_sources.test.tsx | 110 + .../configure_direct_query_data_sources.tsx | 374 ++ ...ct_query_data_source_auth_details.test.tsx | 92 + .../direct_query_data_source_auth_details.tsx | 102 + .../name_row.test.tsx | 75 + .../name_row.tsx | 86 + ...igure_prometheus_data_source.test.tsx.snap | 1021 ++++ ...eview_prometheus_data_source.test.tsx.snap | 381 ++ .../configure_prometheus_data_source.test.tsx | 174 + .../configure_prometheus_data_source.tsx | 196 + .../review_prometheus_data_source.test.tsx | 104 + .../review_prometheus_data_source.tsx | 126 + .../query_permissions.test.tsx | 89 + .../query_permissions.tsx | 103 + .../icons/opensearch_logo.svg | 1 + .../icons/prometheus_logo.svg | 9 + .../icons/query_assistant_logo.svg | 18 + .../icons/s3_logo.svg | 9 + .../public/components/utils.ts | 17 + .../public/constants.ts | 23 + .../mount_management_section.test.tsx | 122 + .../mount_management_section.tsx | 27 +- .../public/plugin.test.ts | 104 +- .../data_source_management/public/plugin.ts | 21 +- .../data_source_management/public/types.ts | 36 + .../application/components/index_pattern.js | 8 +- .../vis_type_timeseries/public/plugin.ts | 2 + .../vis_type_timeseries/public/services.ts | 5 + 71 files changed, 10331 insertions(+), 3522 deletions(-) create mode 100644 changelogs/fragments/7143.yml create mode 100644 changelogs/fragments/7163.yml create mode 100644 changelogs/fragments/7371.yml create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_card_view.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel_header.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.test.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_description.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.test.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_page_header.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.test.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.test.tsx create mode 100644 src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/direct_query_data_source_delete_modal.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/manage_direct_query_data_connections_table.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/__snapshots__/configure_amazon_s3_data_source.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/__snapshots__/review_amazon_s3_data_source.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/configure_amazon_s3_data_source.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/configure_amazon_s3_data_source.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/review_amazon_s3_data_source.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/review_amazon_s3_data_source.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/configure_direct_query_data_sources.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/configure_direct_query_data_sources.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/direct_query_data_source_auth_details.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/direct_query_data_source_auth_details.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/name_row.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/name_row.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/__snapshots__/configure_prometheus_data_source.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/__snapshots__/review_prometheus_data_source.test.tsx.snap create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/configure_prometheus_data_source.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/configure_prometheus_data_source.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/review_prometheus_data_source.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/review_prometheus_data_source.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/query_permissions.test.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/query_permissions.tsx create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/icons/opensearch_logo.svg create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/icons/prometheus_logo.svg create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/icons/query_assistant_logo.svg create mode 100644 src/plugins/data_source_management/public/components/direct_query_data_sources_components/icons/s3_logo.svg create mode 100644 src/plugins/data_source_management/public/constants.ts create mode 100644 src/plugins/data_source_management/public/management_app/mount_management_section.test.tsx diff --git a/changelogs/fragments/7143.yml b/changelogs/fragments/7143.yml new file mode 100644 index 000000000000..dfc286467ab0 --- /dev/null +++ b/changelogs/fragments/7143.yml @@ -0,0 +1,2 @@ +feat: +- [MDS] Observability Datasource Plugin migration with MDS support ([#7143](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7143)) \ No newline at end of file diff --git a/changelogs/fragments/7163.yml b/changelogs/fragments/7163.yml new file mode 100644 index 000000000000..0b9609a4de20 --- /dev/null +++ b/changelogs/fragments/7163.yml @@ -0,0 +1,2 @@ +fix: +- [MDS] Fix the dsm plugin setup when mds feature flag is disabled ([#7163](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7163)) \ No newline at end of file diff --git a/changelogs/fragments/7371.yml b/changelogs/fragments/7371.yml new file mode 100644 index 000000000000..a78822aa5114 --- /dev/null +++ b/changelogs/fragments/7371.yml @@ -0,0 +1,2 @@ +feat: +- [MDS] Observability Datasource Plugin migration with MDS support for Data Connection Table ([#7371](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7371)) \ No newline at end of file diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index 41f97033c5e3..edfb02f6c35c 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -419,6 +419,8 @@ export class DocLinksService { dataSource: { // https://opensearch.org/docs/latest/dashboards/discover/multi-data-sources/ guide: `${OPENSEARCH_DASHBOARDS_VERSIONED_DOCS}discover/multi-data-sources/`, + // https://opensearch.org/docs/latest/dashboards/management/S3-data-source/ + s3DataSource: `${OPENSEARCH_DASHBOARDS_VERSIONED_DOCS}management/S3-data-source/`, }, visualize: { // https://opensearch.org/docs/latest/dashboards/visualize/viz-index/ @@ -821,6 +823,7 @@ export interface DocLinksStart { readonly browser: string; readonly dataSource: { readonly guide: string; + readonly s3DataSource: string; }; readonly visualize: Record; readonly management: Record; diff --git a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap index 215591e2d4c5..68f84dc3394e 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_listing/__snapshots__/dashboard_listing.test.tsx.snap @@ -831,6 +831,7 @@ exports[`dashboard listing hideWriteControls 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -2018,6 +2019,7 @@ exports[`dashboard listing render table listing with initial filters from URL 1` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -3266,6 +3268,7 @@ exports[`dashboard listing renders call to action when no dashboards exist 1`] = "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -4514,6 +4517,7 @@ exports[`dashboard listing renders table rows 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -5762,6 +5766,7 @@ exports[`dashboard listing renders warning when listingLimit is exceeded 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap index acc6217ab4f9..a48e917ce8e3 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap @@ -723,6 +723,7 @@ exports[`Dashboard top nav render in embed mode 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -1732,6 +1733,7 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -2741,6 +2743,7 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -3750,6 +3753,7 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -4759,6 +4763,7 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { @@ -5768,6 +5773,7 @@ exports[`Dashboard top nav render with all components 1`] = ` "browser": "https://opensearch.org/docs/mocked-test-branch/dashboards/browser-compatibility", "dataSource": Object { "guide": "https://opensearch.org/docs/mocked-test-branch/dashboards/discover/multi-data-sources/", + "s3DataSource": "https://opensearch.org/docs/mocked-test-branch/dashboards/management/S3-data-source/", }, "devTools": "https://opensearch.org/docs/mocked-test-branch/dashboards/dev-tools/index-dev/", "dql": Object { diff --git a/src/plugins/data_source_management/opensearch_dashboards.json b/src/plugins/data_source_management/opensearch_dashboards.json index 824f9eacc9f6..691667eee458 100644 --- a/src/plugins/data_source_management/opensearch_dashboards.json +++ b/src/plugins/data_source_management/opensearch_dashboards.json @@ -3,8 +3,8 @@ "version": "opensearchDashboards", "server": false, "ui": true, - "requiredPlugins": ["management", "dataSource", "indexPatternManagement"], - "optionalPlugins": [], + "requiredPlugins": ["management", "indexPatternManagement"], + "optionalPlugins": ["dataSource"], "requiredBundles": ["opensearchDashboardsReact", "dataSource", "opensearchDashboardsUtils"], "extraPublicDirs": ["public/components/utils"] } diff --git a/src/plugins/data_source_management/public/components/breadcrumbs.test.ts b/src/plugins/data_source_management/public/components/breadcrumbs.test.ts index fbf1c62bb7dc..50c6b5a0655e 100644 --- a/src/plugins/data_source_management/public/components/breadcrumbs.test.ts +++ b/src/plugins/data_source_management/public/components/breadcrumbs.test.ts @@ -3,7 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { getCreateBreadcrumbs, getEditBreadcrumbs, getListBreadcrumbs } from './breadcrumbs'; +import { + getCreateBreadcrumbs, + getEditBreadcrumbs, + getListBreadcrumbs, + getCreateOpenSearchDataSourceBreadcrumbs, + getCreateAmazonS3DataSourceBreadcrumbs, + getCreatePrometheusDataSourceBreadcrumbs, +} from './breadcrumbs'; import { mockDataSourceAttributesWithAuth } from '../mocks'; describe('DataSourceManagement: breadcrumbs.ts', () => { @@ -26,4 +33,25 @@ describe('DataSourceManagement: breadcrumbs.ts', () => { expect(bc[1].text).toBe(mockDataSourceAttributesWithAuth.title); expect(bc[1].href).toBe(`/${mockDataSourceAttributesWithAuth.id}`); }); + + test('get create OpenSearch breadcrumb', () => { + const bc = getCreateOpenSearchDataSourceBreadcrumbs(); + expect(bc.length).toBe(3); + expect(bc[2].text).toBe('Open Search'); + expect(bc[2].href).toBe('/configure/OpenSearch'); + }); + + test('get create Amazon S3 breadcrumb', () => { + const bc = getCreateAmazonS3DataSourceBreadcrumbs(); + expect(bc.length).toBe(3); + expect(bc[2].text).toBe('Amazon S3'); + expect(bc[2].href).toBe('/configure/AmazonS3AWSGlue'); + }); + + test('get create Prometheus breadcrumb', () => { + const bc = getCreatePrometheusDataSourceBreadcrumbs(); + expect(bc.length).toBe(3); + expect(bc[2].text).toBe('Prometheus'); + expect(bc[2].href).toBe('/configure/Prometheus'); + }); }); diff --git a/src/plugins/data_source_management/public/components/breadcrumbs.ts b/src/plugins/data_source_management/public/components/breadcrumbs.ts index ad1b470c89d4..cabe632d9dac 100644 --- a/src/plugins/data_source_management/public/components/breadcrumbs.ts +++ b/src/plugins/data_source_management/public/components/breadcrumbs.ts @@ -28,6 +28,50 @@ export function getCreateBreadcrumbs() { }, ]; } +export function getCreateOpenSearchDataSourceBreadcrumbs() { + return [ + ...getCreateBreadcrumbs(), + { + text: i18n.translate( + 'dataSourcesManagement.dataSources.createOpenSearchDataSourceBreadcrumbs', + { + defaultMessage: 'Open Search', + } + ), + href: `/configure/OpenSearch`, + }, + ]; +} + +export function getCreateAmazonS3DataSourceBreadcrumbs() { + return [ + ...getCreateBreadcrumbs(), + { + text: i18n.translate( + 'dataSourcesManagement.dataSources.createAmazonS3DataSourceBreadcrumbs', + { + defaultMessage: 'Amazon S3', + } + ), + href: `/configure/AmazonS3AWSGlue`, + }, + ]; +} + +export function getCreatePrometheusDataSourceBreadcrumbs() { + return [ + ...getCreateBreadcrumbs(), + { + text: i18n.translate( + 'dataSourcesManagement.dataSources.createPrometheusDataSourceBreadcrumbs', + { + defaultMessage: 'Prometheus', + } + ), + href: `/configure/Prometheus`, + }, + ]; +} export function getEditBreadcrumbs(dataSource: DataSourceAttributes) { return [ diff --git a/src/plugins/data_source_management/public/components/constants.tsx b/src/plugins/data_source_management/public/components/constants.tsx index bfb720980132..8d9d369de382 100644 --- a/src/plugins/data_source_management/public/components/constants.tsx +++ b/src/plugins/data_source_management/public/components/constants.tsx @@ -5,6 +5,7 @@ import { i18n } from '@osd/i18n'; import { DataSourceOption } from './data_source_menu/types'; +import { DatasourceType } from '../types'; export const LocalCluster: DataSourceOption = { label: i18n.translate('dataSource.localCluster', { @@ -19,3 +20,29 @@ export const NO_COMPATIBLE_DATASOURCES_MESSAGE = 'No compatible data sources are export const ADD_COMPATIBLE_DATASOURCES_MESSAGE = 'Add a compatible data source.'; export { DEFAULT_DATA_SOURCE_UI_SETTINGS_ID } from '../../common'; + +export const OPENSEARCH_DOCUMENTATION_URL = + 'https://opensearch.org/docs/latest/dashboards/management/data-sources/'; + +export const OPENSEARCH_S3_DOCUMENTATION_URL = + 'https://opensearch.org/docs/latest/dashboards/management/S3-data-source/'; + +export const OPENSEARCH_ACC_DOCUMENTATION_URL = + 'https://opensearch.org/docs/latest/dashboards/management/accelerate-external-data/'; +export const QUERY_RESTRICTED = 'query-restricted'; +export const QUERY_ALL = 'query-all'; + +export const DatasourceTypeToDisplayName: { [key in DatasourceType]: string } = { + PROMETHEUS: 'Prometheus', + S3GLUE: 'Amazon S3', +}; + +export const PrometheusURL = 'Prometheus'; +export const AmazonS3URL = 'AmazonS3AWSGlue'; + +export const UrlToDatasourceType: { [key: string]: DatasourceType } = { + [PrometheusURL]: 'PROMETHEUS', + [AmazonS3URL]: 'S3GLUE', +}; + +export type AuthMethod = 'noauth' | 'basicauth' | 'awssigv4'; diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.test.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.test.tsx index 5bffaee5d3d9..353acd36aaea 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.test.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.test.tsx @@ -107,7 +107,7 @@ describe('Datasource Management: Create Datasource Wizard', () => { await component.find(formIdentifier).first().prop('handleCancel')(); }); - expect(history.push).toBeCalledWith(''); + expect(history.push).toBeCalledWith('/create'); }); }); diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx index 671647c48f48..0be281a20a38 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx @@ -14,7 +14,7 @@ import { DataSourceTableItem, ToastMessageItem, } from '../../types'; -import { getCreateBreadcrumbs } from '../breadcrumbs'; +import { getCreateOpenSearchDataSourceBreadcrumbs } from '../breadcrumbs'; import { CreateDataSourceForm } from './components/create_form'; import { createSingleDataSource, @@ -45,7 +45,7 @@ export const CreateDataSourceWizard: React.FunctionComponent { - setBreadcrumbs(getCreateBreadcrumbs()); + setBreadcrumbs(getCreateOpenSearchDataSourceBreadcrumbs()); getExistingDataSourceNames(); }); @@ -130,7 +130,7 @@ export const CreateDataSourceWizard: React.FunctionComponent props.history.push('')} + handleCancel={() => props.history.push('/create')} existingDatasourceNamesList={existingDatasourceNamesList} /> {isLoading ? : null} diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_card_view.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_card_view.test.tsx.snap new file mode 100644 index 000000000000..e17647be766f --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_card_view.test.tsx.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CreateDataSourceCardView renders correctly 1`] = ` + + + + + } + onClick={[Function]} + title="Amazon S3" + titleElement="span" + /> + + + + } + onClick={[Function]} + title="Prometheus" + titleElement="span" + /> + + + + } + onClick={[Function]} + title="OpenSearch" + titleElement="span" + /> + + + + +`; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel.test.tsx.snap new file mode 100644 index 000000000000..f2c61eecb4db --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel.test.tsx.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CreateDataSourcePanel renders correctly 1`] = ` + + + + + + + + + + + + +`; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel_header.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel_header.test.tsx.snap new file mode 100644 index 000000000000..37a770d5b362 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/__snapshots__/create_data_source_panel_header.test.tsx.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CreateDataSourcePanelHeader renders correctly 1`] = ` + + + +

+ +

+
+ + +

+ +

+
+
+
+`; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.test.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.test.tsx new file mode 100644 index 000000000000..eb63df65ece3 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.test.tsx @@ -0,0 +1,105 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { EuiCard, EuiIcon } from '@elastic/eui'; +import { CreateDataSourceCardView, DatasourceCard } from './create_data_source_card_view'; +import { AMAZON_S3_URL, PROMETHEUS_URL, OPENSEARCH_URL } from '../../constants'; +import { createMemoryHistory } from 'history'; + +describe('CreateDataSourceCardView', () => { + const history = createMemoryHistory(); + const defaultProps = { + history, + featureFlagStatus: true, + }; + + const shallowComponent = (props = defaultProps) => + shallow(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('renders correct datasource cards', () => { + const wrapper = shallowComponent(); + const cards = wrapper.find(EuiCard); + + expect(cards).toHaveLength(3); + + const expectedDatasources: DatasourceCard[] = [ + { + name: 'S3GLUE', + displayName: 'Amazon S3', + description: 'Connect to Amazon S3 via AWS Glue Data Catalog', + displayIcon: ( + + ), + onClick: expect.any(Function), + }, + { + name: 'PROMETHEUS', + displayName: 'Prometheus', + description: 'Connect to Prometheus', + displayIcon: ( + + ), + onClick: expect.any(Function), + }, + { + name: 'OPENSEARCH', + displayName: 'OpenSearch', + description: 'Connect to OpenSearch', + displayIcon: ( + + ), + onClick: expect.any(Function), + }, + ]; + + expectedDatasources.forEach((datasource, index) => { + const card = cards.at(index); + expect(card.prop('title')).toEqual(datasource.displayName); + expect(card.prop('description')).toEqual(datasource.description); + expect(card.prop('icon')?.type).toEqual(datasource.displayIcon?.type); + }); + }); + + test('does not render OpenSearch card when featureFlagStatus is false', () => { + const wrapper = shallowComponent({ ...defaultProps, featureFlagStatus: false }); + const cards = wrapper.find(EuiCard); + + expect(cards).toHaveLength(2); + expect(cards.someWhere((card) => card.prop('title') === 'OpenSearch')).toBe(false); + }); + + test('handles card click events', () => { + const pushSpy = jest.spyOn(history, 'push'); + const wrapper = shallowComponent(); + + const s3Card = wrapper.find('[data-test-subj="datasource_card_s3glue"]'); + const prometheusCard = wrapper.find('[data-test-subj="datasource_card_prometheus"]'); + const opensearchCard = wrapper.find('[data-test-subj="datasource_card_opensearch"]'); + + s3Card.simulate('click'); + expect(pushSpy).toHaveBeenCalledWith(`/configure/${AMAZON_S3_URL}`); + + prometheusCard.simulate('click'); + expect(pushSpy).toHaveBeenCalledWith(`/configure/${PROMETHEUS_URL}`); + + if (defaultProps.featureFlagStatus) { + opensearchCard.simulate('click'); + expect(pushSpy).toHaveBeenCalledWith(`/configure/${OPENSEARCH_URL}`); + } + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.tsx new file mode 100644 index 000000000000..758acb312dc2 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_card_view.tsx @@ -0,0 +1,82 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiPanel, EuiCard, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiIcon } from '@elastic/eui'; +import React from 'react'; +import { History } from 'history'; +import s3Svg from '../direct_query_data_sources_components/icons/s3_logo.svg'; +import prometheusSvg from '../direct_query_data_sources_components/icons/prometheus_logo.svg'; +import opensearchLogSvg from '../direct_query_data_sources_components/icons/opensearch_logo.svg'; +import { AMAZON_S3_URL, PROMETHEUS_URL, OPENSEARCH_URL } from '../../constants'; + +export interface DatasourceCard { + name: string; + displayName: string; + description: string; + displayIcon: JSX.Element; + onClick: () => void; +} + +interface CreateDataSourceCardViewProps { + history: History; + featureFlagStatus: boolean; +} + +export function CreateDataSourceCardView({ + history, + featureFlagStatus, +}: CreateDataSourceCardViewProps) { + const Datasources: DatasourceCard[] = [ + { + name: 'S3GLUE', + displayName: 'Amazon S3', + description: 'Connect to Amazon S3 via AWS Glue Data Catalog', + displayIcon: , + onClick: () => history.push(`/configure/${AMAZON_S3_URL}`), + }, + { + name: 'PROMETHEUS', + displayName: 'Prometheus', + description: 'Connect to Prometheus', + displayIcon: , + onClick: () => history.push(`/configure/${PROMETHEUS_URL}`), + }, + ...(featureFlagStatus + ? [ + { + name: 'OPENSEARCH', + displayName: 'OpenSearch', + description: 'Connect to OpenSearch', + displayIcon: , + onClick: () => history.push(`/configure/${OPENSEARCH_URL}`), + }, + ] + : []), + ]; + + const renderRows = (datasources: DatasourceCard[]) => { + return ( + <> + + {datasources.map((i) => ( + + + + ))} + + + + ); + }; + + return {renderRows(Datasources)}; +} diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_description.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_description.tsx new file mode 100644 index 000000000000..91f13c66624e --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_description.tsx @@ -0,0 +1,24 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiSpacer, EuiText, EuiTitle, EuiHorizontalRule } from '@elastic/eui'; +import React from 'react'; + +export const NewDatasourceDescription = () => { + return ( +
+ +

Create a new data source

+
+ + + + Connect to a compatible data source or compute engine to bring your data into OpenSearch and + OpenSearch Dashboards. + + +
+ ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx new file mode 100644 index 000000000000..5884dadc5876 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx @@ -0,0 +1,64 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { CreateDataSourcePanel } from './create_data_source_panel'; +import { CreateDataSourcePanelHeader } from './create_data_source_panel_header'; +import { CreateDataSourceCardView } from './create_data_source_card_view'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getCreateBreadcrumbs } from '../breadcrumbs'; +import { DataSourceManagementContext } from '../../types'; +import { RouteComponentProps } from 'react-router-dom'; + +jest.mock('../../../../opensearch_dashboards_react/public'); +jest.mock('../breadcrumbs'); +jest.mock('./create_data_source_panel_header', () => ({ + CreateDataSourcePanelHeader: () =>
CreateDataSourcePanelHeader
, +})); +jest.mock('./create_data_source_card_view', () => ({ + CreateDataSourceCardView: () =>
CreateDataSourceCardView
, +})); + +describe('CreateDataSourcePanel', () => { + const mockedContext = { + services: { + chrome: {}, + setBreadcrumbs: jest.fn(), + notifications: { + toasts: { + addSuccess: jest.fn(), + addDanger: jest.fn(), + }, + }, + uiSettings: {}, + }, + }; + + beforeAll(() => { + (useOpenSearchDashboards as jest.Mock).mockReturnValue(mockedContext); + (getCreateBreadcrumbs as jest.Mock).mockReturnValue([{ text: 'Create Data Source' }]); + }); + + const defaultProps: RouteComponentProps & { featureFlagStatus: boolean } = { + featureFlagStatus: true, + history: { push: jest.fn() } as any, + location: {} as any, + match: {} as any, + }; + + const shallowComponent = (props = defaultProps) => shallow(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('renders CreateDataSourcePanelHeader and CreateDataSourceCardView', () => { + const wrapper = shallowComponent(); + expect(wrapper.find(CreateDataSourcePanelHeader)).toHaveLength(1); + expect(wrapper.find(CreateDataSourceCardView)).toHaveLength(1); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx new file mode 100644 index 000000000000..7e6761d51254 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFlexGroup, EuiFlexItem, EuiPageHeader, EuiPanel } from '@elastic/eui'; +import React, { useEffect } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { CreateDataSourcePanelHeader } from './create_data_source_panel_header'; +import { CreateDataSourceCardView } from './create_data_source_card_view'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getCreateBreadcrumbs } from '../breadcrumbs'; +import { DataSourceManagementContext } from '../../types'; + +interface CreateDataSourcePanelProps extends RouteComponentProps { + featureFlagStatus: boolean; +} + +export const CreateDataSourcePanel: React.FC = ({ + featureFlagStatus, + ...props +}) => { + const { + chrome, + setBreadcrumbs, + notifications: { toasts }, + uiSettings, + } = useOpenSearchDashboards().services; + + useEffect(() => { + setBreadcrumbs(getCreateBreadcrumbs()); + }, [setBreadcrumbs]); + + return ( + + + + + + + + + + + + + ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.test.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.test.tsx new file mode 100644 index 000000000000..05af9a27d554 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.test.tsx @@ -0,0 +1,35 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { CreateDataSourcePanelHeader } from './create_data_source_panel_header'; +import { EuiFlexGroup, EuiTitle, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@osd/i18n/react'; + +describe('CreateDataSourcePanelHeader', () => { + const shallowComponent = () => shallow(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('contains correct title and description', () => { + const wrapper = shallowComponent(); + + const titleMessage = wrapper.find(EuiTitle).find(FormattedMessage); + expect(titleMessage.prop('id')).toEqual('dataSourcesManagement.createDataSourcePanel.title'); + expect(titleMessage.prop('defaultMessage')).toEqual('Create Data Source'); + + const descriptionMessage = wrapper.find(EuiText).find(FormattedMessage); + expect(descriptionMessage.prop('id')).toEqual( + 'dataSourcesManagement.createDataSourcePanel.description' + ); + expect(descriptionMessage.prop('defaultMessage')).toEqual( + 'Select a data source type to get started.' + ); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.tsx new file mode 100644 index 000000000000..ac3cec5cdddc --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel_header.tsx @@ -0,0 +1,34 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@osd/i18n/react'; + +export const CreateDataSourcePanelHeader: React.FC = () => { + return ( + + + +

+ +

+
+ + +

+ +

+
+
+
+ ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap new file mode 100644 index 000000000000..4db09dab5b2a --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap @@ -0,0 +1,75 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DataSourceHomePanel renders correctly 1`] = ` + + + + + + + + + + + + + + + + + + + Direct query connections + + + OpenSearch connections + + + + + + + + + +`; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_page_header.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_page_header.test.tsx.snap new file mode 100644 index 000000000000..ab527a7307f6 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_page_header.test.tsx.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DataSourceHeader renders correctly 1`] = ` + + + +

+ +

+
+ + +

+ +

+
+
+
+`; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.test.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.test.tsx new file mode 100644 index 000000000000..cbc1f015c6f3 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.test.tsx @@ -0,0 +1,99 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow, mount } from 'enzyme'; +import { RouteComponentProps } from 'react-router-dom'; +import { EuiTab } from '@elastic/eui'; +import { DataSourceHomePanel } from './data_source_home_panel'; +import { DataSourceTableWithRouter } from '../data_source_table/data_source_table'; +import { ManageDirectQueryDataConnectionsTable } from '../direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table'; +import { CreateButton } from '../create_button'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getListBreadcrumbs } from '../breadcrumbs'; + +jest.mock('../../../../opensearch_dashboards_react/public'); +jest.mock('../breadcrumbs'); +jest.mock('../data_source_table/data_source_table', () => ({ + DataSourceTableWithRouter: () =>
DataSourceTableWithRouter
, +})); +jest.mock( + '../direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table', + () => ({ + ManageDirectQueryDataConnectionsTable: () =>
ManageDirectQueryDataConnectionsTable
, + }) +); +jest.mock('../create_button', () => ({ + CreateButton: ({ history, dataTestSubj }) => ( + + ), +})); + +describe('DataSourceHomePanel', () => { + const mockedContext = { + services: { + setBreadcrumbs: jest.fn(), + notifications: {}, + http: {}, + savedObjects: {}, + uiSettings: {}, + }, + }; + + beforeAll(() => { + (useOpenSearchDashboards as jest.Mock).mockReturnValue(mockedContext); + (getListBreadcrumbs as jest.Mock).mockReturnValue([{ text: 'Data sources' }]); + }); + + const defaultProps: RouteComponentProps & { featureFlagStatus: boolean } = { + featureFlagStatus: true, + history: { push: jest.fn() } as any, + location: {} as any, + match: {} as any, + }; + + const shallowComponent = (props = defaultProps) => shallow(); + const mountComponent = (props = defaultProps) => mount(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('renders DataSourceTableWithRouter when manageOpensearchDataSources tab is selected', () => { + const wrapper = mountComponent(); + wrapper.find(EuiTab).at(1).simulate('click'); + expect(wrapper.find(DataSourceTableWithRouter)).toHaveLength(1); + expect(wrapper.find(ManageDirectQueryDataConnectionsTable)).toHaveLength(0); + }); + + test('renders ManageDirectQueryDataConnectionsTable when manageDirectQueryDataSources tab is selected', () => { + const wrapper = mountComponent(); + wrapper.find(EuiTab).at(0).simulate('click'); + expect(wrapper.find(ManageDirectQueryDataConnectionsTable)).toHaveLength(1); + expect(wrapper.find(DataSourceTableWithRouter)).toHaveLength(0); + }); + + test('handles tab changes', () => { + const wrapper = mountComponent(); + expect(wrapper.find(ManageDirectQueryDataConnectionsTable)).toHaveLength(1); + wrapper.find(EuiTab).at(1).simulate('click'); + expect(wrapper.find(DataSourceTableWithRouter)).toHaveLength(1); + }); + + test('does not render OpenSearch connections tab when featureFlagStatus is false', () => { + const wrapper = shallowComponent({ ...defaultProps, featureFlagStatus: false }); + expect(wrapper.find(EuiTab)).toHaveLength(1); + }); + + test('calls history.push when CreateButton is clicked', () => { + const historyMock = { push: jest.fn() }; + const wrapper = mountComponent({ ...defaultProps, history: historyMock }); + wrapper.find('button[data-test-subj="createDataSourceButton"]').simulate('click'); + expect(historyMock.push).toHaveBeenCalledWith('/create'); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx new file mode 100644 index 000000000000..3cedbb9641c0 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx @@ -0,0 +1,111 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect, useState } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiTabs, + EuiTab, + EuiPageHeader, + EuiPanel, +} from '@elastic/eui'; +import { DataSourceHeader } from './data_source_page_header'; +import { DataSourceTableWithRouter } from '../data_source_table/data_source_table'; +import { ManageDirectQueryDataConnectionsTable } from '../direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table'; +import { CreateButton } from '../create_button'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { getListBreadcrumbs } from '../breadcrumbs'; +import { DataSourceManagementContext } from '../../types'; + +interface DataSourceHomePanelProps extends RouteComponentProps { + featureFlagStatus: boolean; +} + +export const DataSourceHomePanel: React.FC = ({ + featureFlagStatus, + ...props +}) => { + const { setBreadcrumbs, notifications, http, savedObjects, uiSettings } = useOpenSearchDashboards< + DataSourceManagementContext + >().services; + + const [selectedTabId, setSelectedTabId] = useState('manageDirectQueryDataSources'); + + useEffect(() => { + setBreadcrumbs(getListBreadcrumbs()); + }, [setBreadcrumbs]); + + const onSelectedTabChanged = (id: string) => { + setSelectedTabId(id); + }; + + const tabs = [ + { + id: 'manageDirectQueryDataSources', + name: 'Direct query connections', + }, + ...(featureFlagStatus + ? [ + { + id: 'manageOpensearchDataSources', + name: 'OpenSearch connections', + }, + ] + : []), + ]; + + const renderTabs = () => { + return tabs.map((tab) => ( + onSelectedTabChanged(tab.id)} + isSelected={tab.id === selectedTabId} + key={tab.id} + > + {tab.name} + + )); + }; + + return ( + + + + + + + + + + + + + + + + + {renderTabs()} + + + + {selectedTabId === 'manageOpensearchDataSources' && featureFlagStatus && ( + + )} + {selectedTabId === 'manageDirectQueryDataSources' && ( + + )} + + + + ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.test.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.test.tsx new file mode 100644 index 000000000000..8773bb0b3055 --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.test.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { DataSourceHeader } from './data_source_page_header'; +import { EuiTitle, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@osd/i18n/react'; + +describe('DataSourceHeader', () => { + const defaultProps = { + history: {} as any, + location: {} as any, + match: {} as any, + }; + + const shallowComponent = (props = defaultProps) => shallow(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('contains correct title and description', () => { + const wrapper = shallowComponent(); + + const titleMessage = wrapper.find(EuiTitle).find(FormattedMessage); + expect(titleMessage.prop('id')).toEqual('dataSourcesManagement.dataSourcesTable.title'); + expect(titleMessage.prop('defaultMessage')).toEqual('Data Sources'); + + const descriptionMessage = wrapper.find(EuiText).find(FormattedMessage); + expect(descriptionMessage.prop('id')).toEqual( + 'dataSourcesManagement.dataSourcesTable.description' + ); + expect(descriptionMessage.prop('defaultMessage')).toEqual( + 'Create and manage data source connections.' + ); + }); +}); diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.tsx new file mode 100644 index 000000000000..9fa99fa9296d --- /dev/null +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_page_header.tsx @@ -0,0 +1,37 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@osd/i18n/react'; +import { RouteComponentProps } from 'react-router-dom'; + +type DataSourceHeaderProps = RouteComponentProps; + +export const DataSourceHeader: React.FC = () => { + return ( + + + +

+ +

+
+ + +

+ +

+
+
+
+ ); +}; diff --git a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap index 05fd70496974..842c3e3d07ba 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap @@ -30,317 +30,145 @@ exports[`DataSourceTable should get datasources failed should render empty table location={Object {}} match={Object {}} > - - +
+ +
-
- +
-
- -
- -

- - - Data Sources - - -

-
- -
- - -
-

- - - Create and manage data source connections to help you retrieve data from multiple OpenSearch compatible sources. - - -

-
-
-
- - -
- - - - - - - -
-
-
- - -
- - -
- - + No Data Source Connections have been created yet. + + +
+ + +
+ + + -
- -
- - - No Data Source Connections have been created yet. - - -
-
- -
- - - - - - - - -
- - -
- -
- - + + + + + + + + +
+ + +
+ `; @@ -452,75 +280,247 @@ exports[`DataSourceTable should get datasources successful should render normall location={Object {}} match={Object {}} > - + + Delete + + + + + + , + } + } + selection={ + Object { + "onSelectionChange": [Function], + } + } + sorting={ + Object { + "sort": Object { + "direction": "asc", + "field": "title", + }, + } + } + tableLayout="fixed" > - -
+ + + Delete + + + + + + + } >
- -

- - - Data Sources - - -

-
- -
- - -
-

- +

- - Create and manage data source connections to help you retrieve data from multiple OpenSearch compatible sources. - - -

-
- +
+ + + + +
+ + + + + +
+
+
+
+ + +
- - - - - - - + + + + +
+
- -
- - + +
+ + - - Delete - - - - - - , - } + "name": "Description", + "sortable": [Function], + "truncateText": true, + }, + ] + } + isSelectable={true} + itemId="id" + items={ + Array [ + Object { + "description": "alpha test datasource", + "id": "alpha-test", + "sort": "alpha-test", + "title": "alpha-test", + }, + Object { + "description": "beta test datasource", + "id": "beta-test", + "sort": "beta-test", + "title": "beta-test", + }, + Object { + "description": "test datasource", + "id": "test", + "sort": "test", + "title": "test", + }, + Object { + "description": "test datasource2", + "id": "test2", + "sort": "test", + "title": "test", + }, + ] + } + loading={false} + noItemsMessage="No items found" + onChange={[Function]} + pagination={ + Object { + "hidePerPageOptions": undefined, + "pageIndex": 0, + "pageSize": 10, + "pageSizeOptions": Array [ + 5, + 10, + 25, + 50, + ], + "totalItemCount": 4, } - selection={ - Object { - "onSelectionChange": [Function], - } + } + responsive={true} + selection={ + Object { + "onSelectionChange": [Function], } - sorting={ - Object { - "sort": Object { - "direction": "asc", - "field": "title", - }, - } + } + sorting={ + Object { + "allowNeutralSort": false, + "sort": Object { + "direction": "asc", + "field": "Title", + }, } - tableLayout="fixed" + } + tableLayout="fixed" + > +
- - - Delete - - - - - - - } - > - +
-
- -
- - -
+
+
+ Select all rows +
-
-
-
-
-
- -
+ +
+
+ - -
- - + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" > - - - -
-
-
- -
-
-
- -
- - + + + + + + + Sorting + + + + + + +
+
+ +
+ +
+ +
+ +
+ + -
-
- -
+ + + + + + + + + +
+ + +
+ +
+
+ + +
+ + + + + + + + + + + + + + + + + + - -
-
-
- - + + +
- +
+ -
- - - + -
-
- - - -
-
-
-
- + alpha-test + + + + +
- -
- -
- - - + + + + + + + - - - - - - - +
-
- - +
+
+ + + + + + +
- - + + + + + - - - - - + + + + + + + - - + - - - - + + + + + + - - + + + + + - - - - - + + + + + + + - - - - + + + + + + + + + - - + + + + + + - - - - + + + + + + + + + + + + +
+
+ + alpha test datasource + +
+
+ - -
-
- - -
- -
-
- - -
-
+
-
+
+ -
+
-
- -
-
- - -
- -
-
- - + +
-
+
+ Title +
+
+ -
-
- Title -
-
- - - -
-
+ -
- alpha test datasource + + Default + + + + -
-
-
-
- - -
- -
-
- - -
-
+
+ -
- Title -
-
- - - + +
-
+
+ Title +
+
+ -
-
- beta test datasource + + test + -
-
+
+ + test datasource2 + +
+
+
+
+ +
+ +
+ + + +
+ +
+ + + : + 10 + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="none" + > +
- - - -
- - + + + -
- -
-
- - -
- - - - -
- Title -
-
- - - - - - - - - Default - - - - - - - - -
- -
- - -
- - test datasource - -
- -
- - - - - - -
- - -
- -
-
- - -
- - - - -
- Title -
-
- - - -
- -
- - -
- - test datasource2 + Rows per page + + : + 10 + -
- -
- - - - - - -
- -
- + + +
+
+ +
+ +
- - - -
- -
- - - : - 10 - + + -
-
- -
-
-
-
-
- - - -
-
-
+
+
- -
- -
- -
- - +
+ +
+ +
+ +
+ `; @@ -3576,1246 +3155,61 @@ exports[`DataSourceTable should not manage datasources when canManageDataSource location={Object {}} match={Object {}} > - +
+ + - -
- +
-
- -
- -

- - - Data Sources - - -

-
- -
- - -
-

- - - Create and manage data source connections to help you retrieve data from multiple OpenSearch compatible sources. - - -

-
-
-
- - -
- - - - - - - -
-
-
- - -
- - -
- - -
- -
- - - No Data Source Connections have been created yet. - - -
-
- -
- -
- - -
- -
- - + + No Data Source Connections have been created yet. + + +
+ + +
+ +
+
+ +
+ `; diff --git a/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx b/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx index 0f1abb2d755b..9a4264f1ec4f 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx +++ b/src/plugins/data_source_management/public/components/data_source_table/data_source_table.tsx @@ -8,21 +8,17 @@ import { EuiButton, EuiButtonEmpty, EuiConfirmModal, - EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, - EuiPageContent, EuiPanel, EuiSpacer, EuiText, - EuiTitle, } from '@elastic/eui'; import React, { useState } from 'react'; import { RouteComponentProps, withRouter } from 'react-router-dom'; import { useEffectOnce } from 'react-use'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; -import { getListBreadcrumbs } from '../breadcrumbs'; import { reactRouterNavigate, useOpenSearchDashboards, @@ -70,9 +66,6 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { /* useEffectOnce hook to avoid these methods called multiple times when state is updated. */ useEffectOnce(() => { - /* Update breadcrumb*/ - setBreadcrumbs(getListBreadcrumbs()); - /* Browser - Page Title */ chrome.docTitle.change( i18n.translate('dataSourcesManagement.dataSourcesTable.dataSourcesTitle', { @@ -202,28 +195,22 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { defaultFocusedButton="confirm" >

- { - - } +

- { - - } +

- { - - } +

) : null; @@ -292,48 +279,6 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { }; /* Render Ui elements*/ - /* Create Data Source button */ - const createButton = ; - const createButtonEmptyState = ( - - ); - - /* Render header*/ - const renderHeader = () => { - return ( - - - -

- { - - } -

-
- - -

- { - - } -

-
-
- {createButton} -
- ); - }; - /* Render table */ const renderTableContent = () => { return ( @@ -356,6 +301,14 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { }; const renderEmptyState = () => { + const createButtonEmptyState = ( + + ); + return ( <> @@ -366,12 +319,10 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { data-test-subj="datasourceTableEmptyState" > - { - - } + {canManageDataSource ? createButtonEmptyState : null} @@ -381,34 +332,15 @@ export const DataSourceTable = ({ history }: RouteComponentProps) => { ); }; - const renderContent = () => { - return ( - <> - - {/* Header */} - {renderHeader()} - - - - {/* Delete confirmation modal*/} - {tableRenderDeleteModal()} - - {!isLoading && (!dataSources || !dataSources.length) - ? renderEmptyState() - : renderTableContent()} - - {isDeleting ? : null} - - ); - }; - - return renderContent(); + return ( + <> + {tableRenderDeleteModal()} + {!isLoading && (!dataSources || !dataSources.length) + ? renderEmptyState() + : renderTableContent()} + {isDeleting ? : null} + + ); }; export const DataSourceTableWithRouter = withRouter(DataSourceTable); diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/direct_query_data_source_delete_modal.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/direct_query_data_source_delete_modal.test.tsx.snap new file mode 100644 index 000000000000..1865cefc626b --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/direct_query_data_source_delete_modal.test.tsx.snap @@ -0,0 +1,60 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DeleteModal renders correctly 1`] = ` + + + + + Delete Item + + + + + Are you sure you want to delete this item? + + + The action cannot be undone. + + + + + + + + + + + Cancel + + + Delete + + + + +`; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/manage_direct_query_data_connections_table.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/manage_direct_query_data_connections_table.test.tsx.snap new file mode 100644 index 000000000000..9177634e0a2f --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/__snapshots__/manage_direct_query_data_connections_table.test.tsx.snap @@ -0,0 +1,920 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ManageDirectQueryDataConnectionsTable renders correctly 1`] = ` + + +
+ +
+ + +
+ +
+ +
+ +
+ + +
+ + +
+ + + +
+
+ + + Local cluster + + + +
+ +
+
+ +
+ +
+ + + + + + + + +
+
+
+
+ + +
+ + +
+ + +
+ + +
+
+ + + + +
+ + + + + +
+
+
+
+
+
+
+
+
+ + +
+ + + +
+
+ +
+ +
+ +
+ + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + Name + + + + + + + + + + + + Status + + + + + + + + + + + + Actions + + + + + +
+
+ + No items found + +
+
+
+
+
+ + +
+ +
+ +
+ + +`; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.test.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.test.tsx new file mode 100644 index 000000000000..a766ab4617c8 --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.test.tsx @@ -0,0 +1,76 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { shallow, mount } from 'enzyme'; +import { DeleteModal } from './direct_query_data_source_delete_modal'; +import { + EuiButtonEmpty, + EuiFieldText, + EuiModalBody, + EuiModalHeaderTitle, + EuiText, +} from '@elastic/eui'; + +describe('DeleteModal', () => { + const defaultProps = { + onCancel: jest.fn(), + onConfirm: jest.fn(), + title: 'Delete Item', + message: 'Are you sure you want to delete this item?', + prompt: 'delete', + }; + + const shallowComponent = (props = defaultProps) => shallow(); + const mountComponent = (props = defaultProps) => mount(); + + test('renders correctly', () => { + const wrapper = shallowComponent(); + expect(wrapper).toMatchSnapshot(); + }); + + test('displays the correct title and message', () => { + const wrapper = mountComponent(); + expect(wrapper.find(EuiModalHeaderTitle).text()).toEqual('Delete Item'); + expect(wrapper.find(EuiModalBody).find(EuiText).at(0).text()).toEqual( + 'Are you sure you want to delete this item?' + ); + }); + + test('disables the delete button initially', () => { + const wrapper = mountComponent(); + const deleteButton = wrapper.find('button[data-test-subj="popoverModal__deleteButton"]'); + expect(deleteButton.prop('disabled')).toBe(true); + }); + + test('enables the delete button when the correct prompt is entered', () => { + const wrapper = mountComponent(); + const input = wrapper.find(EuiFieldText); + input.simulate('change', { target: { value: 'delete' } }); + wrapper.update(); + const deleteButton = wrapper.find('button[data-test-subj="popoverModal__deleteButton"]'); + setTimeout(() => { + expect(deleteButton.prop('disabled')).toBe(false); + }, 1000); + }); + + test('calls onCancel when the cancel button is clicked', () => { + const wrapper = mountComponent(); + wrapper.find(EuiButtonEmpty).simulate('click'); + expect(defaultProps.onCancel).toHaveBeenCalled(); + }); + + test('calls onConfirm when the delete button is clicked', () => { + const wrapper = mountComponent(); + const input = wrapper.find(EuiFieldText); + input.simulate('change', { target: { value: 'delete' } }); + wrapper.update(); + const deleteButton = wrapper.find('button[data-test-subj="popoverModal__deleteButton"]'); + setTimeout(() => { + deleteButton.simulate('click'); + expect(defaultProps.onConfirm).toHaveBeenCalled(); + }, 1000); + }); +}); diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.tsx new file mode 100644 index 000000000000..bf343fa6b5ca --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/direct_query_data_source_delete_modal.tsx @@ -0,0 +1,82 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { + EuiOverlayMask, + EuiModal, + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiSpacer, + EuiText, +} from '@elastic/eui'; + +export const DeleteModal = ({ + onCancel, + onConfirm, + title, + message, + prompt, +}: { + onCancel: ( + event?: React.KeyboardEvent | React.MouseEvent + ) => void; + onConfirm: (event?: React.MouseEvent) => void; + title: string; + message: string; + prompt?: string; +}) => { + const [value, setValue] = useState(''); + const onChange = (e: React.ChangeEvent) => { + setValue(e.target.value); + }; + const deletePrompt = prompt ?? 'delete'; + return ( + + + + {title} + + + + {message} + The action cannot be undone. + + + + onChange(e)} + data-test-subj="popoverModal__deleteTextInput" + /> + + + + + + Cancel + onConfirm()} + color="danger" + fill + disabled={value !== deletePrompt} + data-test-subj="popoverModal__deleteButton" + > + Delete + + + + + ); +}; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.test.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.test.tsx new file mode 100644 index 000000000000..06d1dc61d166 --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.test.tsx @@ -0,0 +1,128 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mount, ReactWrapper } from 'enzyme'; +import { + HttpStart, + NotificationsStart, + SavedObjectsStart, + IUiSettingsClient, +} from 'opensearch-dashboards/public'; +import { EuiFieldSearch, EuiInMemoryTable, EuiLoadingSpinner } from '@elastic/eui'; +import { ManageDirectQueryDataConnectionsTable } from './manage_direct_query_data_connections_table'; + +const mockHttp = ({ + get: jest.fn(), +} as unknown) as jest.Mocked; + +const mockNotifications = ({ + toasts: { addDanger: jest.fn(), addSuccess: jest.fn(), addWarning: jest.fn() }, +} as unknown) as jest.Mocked; + +const mockSavedObjects = ({ + client: {}, +} as unknown) as jest.Mocked; + +const mockUiSettings = ({} as unknown) as jest.Mocked; + +const defaultProps = { + http: mockHttp, + notifications: mockNotifications, + savedObjects: mockSavedObjects, + uiSettings: mockUiSettings, + featureFlagStatus: true, +}; + +describe('ManageDirectQueryDataConnectionsTable', () => { + let wrapper: ReactWrapper; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + test('renders correctly', async () => { + mockHttp.get.mockResolvedValueOnce([]); // Mock an empty array for the initial fetch + + await act(async () => { + wrapper = mount(); + }); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + }); + + test('displays loading spinner while fetching data', async () => { + let resolveFetch; + const fetchPromise = new Promise((resolve) => { + resolveFetch = resolve; + }); + mockHttp.get.mockImplementation(() => fetchPromise); + + await act(async () => { + wrapper = mount(); + }); + + wrapper.update(); + + expect(wrapper.find(EuiLoadingSpinner).exists()).toBe(true); + + // Simulate fetch completion + await act(async () => { + resolveFetch([]); + }); + wrapper.update(); + }); + + test('fetches and displays data connections', async () => { + mockHttp.get.mockResolvedValueOnce([ + { + name: 'Test Connection', + connector: 'S3GLUE', + status: 'ACTIVE', + }, + ]); + + await act(async () => { + wrapper = mount(); + }); + wrapper.update(); + + expect(wrapper.find(EuiInMemoryTable).prop('items')).toHaveLength(1); + }); + + test('filters data connections based on search text', async () => { + mockHttp.get.mockResolvedValueOnce([ + { + name: 'Test Connection', + connector: 'S3GLUE', + status: 'ACTIVE', + }, + { + name: 'Another Connection', + connector: 'PROMETHEUS', + status: 'INACTIVE', + }, + ]); + + await act(async () => { + wrapper = mount(); + }); + wrapper.update(); + + const searchInput = wrapper.find(EuiFieldSearch); + expect(searchInput.exists()).toBe(true); + + await act(async () => { + searchInput.find('input').simulate('change', { target: { value: 'Test' } }); + }); + wrapper.update(); + + const table = wrapper.find(EuiInMemoryTable); + const items = table.prop('items') as any[]; + expect(items).toHaveLength(1); + expect(items[0].name).toBe('Test Connection'); + }); +}); diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx new file mode 100644 index 000000000000..0209067d2078 --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx @@ -0,0 +1,283 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFlexGroup, + EuiFlexItem, + EuiHealth, + EuiIcon, + EuiInMemoryTable, + EuiLink, + EuiOverlayMask, + EuiPageBody, + EuiSpacer, + EuiTableFieldDataColumnType, + EuiFieldSearch, + EuiLoadingSpinner, + EuiText, +} from '@elastic/eui'; +import React, { useCallback, useEffect, useState } from 'react'; +import { + HttpStart, + IUiSettingsClient, + NotificationsStart, + SavedObjectsStart, +} from 'opensearch-dashboards/public'; +import { + DirectQueryDatasourceDetails, + DirectQueryDatasourceStatus, + DirectQueryDatasourceType, +} from '../../../types'; +import { DeleteModal } from './direct_query_data_source_delete_modal'; +import PrometheusLogo from '../icons/prometheus_logo.svg'; +import S3Logo from '../icons/s3_logo.svg'; +import { DataSourceSelector } from '../../data_source_selector'; +import { DataSourceOption } from '../../data_source_menu/types'; + +interface DataConnection { + connectionType: DirectQueryDatasourceType; + name: string; + dsStatus: DirectQueryDatasourceStatus; +} + +interface ManageDirectQueryDataConnectionsTableProps { + http: HttpStart; + notifications: NotificationsStart; + savedObjects: SavedObjectsStart; + uiSettings: IUiSettingsClient; + featureFlagStatus: boolean; +} + +// Custom truncate function +const truncate = (text: string, length: number) => { + if (text.length <= length) return text; + return text.substring(0, length) + '...'; +}; + +export const ManageDirectQueryDataConnectionsTable: React.FC = ({ + http, + notifications, + savedObjects, + uiSettings, + featureFlagStatus, +}) => { + const [data, setData] = useState([]); + const [isModalVisible, setIsModalVisible] = useState(false); + const [modalLayout, setModalLayout] = useState(); + const [selectedDataSourceId, setSelectedDataSourceId] = useState(''); + const [searchText, setSearchText] = useState(''); + const [isLoading, setIsLoading] = useState(false); + + const fetchDataSources = useCallback(() => { + const endpoint = + featureFlagStatus && selectedDataSourceId !== undefined + ? `/api/dataconnections/dataSourceMDSId=${selectedDataSourceId}` + : `/api/dataconnections`; + + setIsLoading(true); + + http + .get(endpoint) + .then((res: DirectQueryDatasourceDetails[]) => { + const dataConnections = res.map((dataConnection: DirectQueryDatasourceDetails) => ({ + name: dataConnection.name, + connectionType: dataConnection.connector, + dsStatus: dataConnection.status, + })); + setData(dataConnections); + }) + .catch((err) => { + notifications.toasts.addDanger('Could not fetch data sources'); + }) + .finally(() => { + setIsLoading(false); + }); + }, [http, notifications.toasts, selectedDataSourceId, featureFlagStatus]); + + useEffect(() => { + fetchDataSources(); + }, [fetchDataSources]); + + const handleSelectedDataSourceChange = (e: DataSourceOption[]) => { + const dataSourceId = e[0] ? e[0].id : ''; + setSelectedDataSourceId(dataSourceId); + }; + + const deleteConnection = (connectionName: string) => { + setData(data.filter((connection) => !(connection.name === connectionName))); + }; + + const displayDeleteModal = (connectionName: string) => { + setModalLayout( + { + setIsModalVisible(false); + deleteConnection(connectionName); + }} + onCancel={() => { + setIsModalVisible(false); + }} + title={`Delete ${connectionName}`} + message={`Are you sure you want to delete ${connectionName}?`} + /> + ); + setIsModalVisible(true); + }; + + const actions = [ + { + name: (datasource: DataConnection) => + `Query in ${ + datasource.connectionType === 'PROMETHEUS' ? 'Metrics Analytics' : 'Observability Logs' + }`, + isPrimary: true, + icon: 'discoverApp', + type: 'icon', + onClick: () => {}, + 'data-test-subj': 'action-query', + }, + { + name: 'Accelerate performance', + isPrimary: false, + icon: 'bolt', + type: 'icon', + available: (datasource: DataConnection) => datasource.connectionType !== 'PROMETHEUS', + onClick: () => {}, + 'data-test-subj': 'action-accelerate', + }, + { + name: 'Integrate data', + isPrimary: false, + icon: 'integrationGeneral', + type: 'icon', + available: (datasource: DataConnection) => datasource.connectionType !== 'PROMETHEUS', + onClick: () => {}, + 'data-test-subj': 'action-integrate', + }, + { + name: 'Delete', + description: 'Delete this data source', + icon: 'trash', + color: 'danger', + type: 'icon', + onClick: (datasource: DataConnection) => displayDeleteModal(datasource.name), + isPrimary: false, + 'data-test-subj': 'action-delete', + }, + ]; + + const icon = (record: DataConnection) => { + switch (record.connectionType) { + case 'S3GLUE': + return ; + case 'PROMETHEUS': + return ; + default: + return <>; + } + }; + + const tableColumns = [ + { + field: 'name', + name: 'Name', + sortable: true, + truncateText: true, + render: (value, record: DataConnection) => ( + + {icon(record)} + + + {truncate(record.name, 100)} + + + + ), + }, + { + field: 'status', + name: 'Status', + sortable: true, + truncateText: true, + render: (value, record: DataConnection) => + record.dsStatus === 'ACTIVE' ? ( + Active + ) : ( + Inactive + ), + }, + { + field: 'actions', + name: 'Actions', + actions, + }, + ] as Array>; + + const customSearchBar = ( + + {featureFlagStatus && ( + + + + )} + + setSearchText(e.target.value)} + isClearable + fullWidth={true} + /> + + + ); + + const entries = data.filter((dataconnection) => + dataconnection.name.toLowerCase().includes(searchText.toLowerCase()) + ); + + return ( + + + + + {customSearchBar} + + {isLoading ? ( +
+ + + Loading direct query data connections... +
+ ) : ( + + )} +
+
+ {isModalVisible && modalLayout} +
+ ); +}; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap new file mode 100644 index 000000000000..1eb30007471b --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap @@ -0,0 +1,187 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`QueryPermissionsConfiguration renders correctly 1`] = ` + + + +
+ +
+ +
+ +
+

+ Query permissions +

+
+
+ +
+

+ Control which OpenSearch roles have permission to query and index data from this data source. +

+
+
+
+
+ +
+ + Query access level + , + "compressed": undefined, + } + } + name="query-radio-group" + onChange={[Function]} + options={ + Array [ + Object { + "disabled": false, + "id": "query-restricted", + "label": "Restricted - accessible by users with specific OpenSearch roles", + }, + Object { + "disabled": false, + "id": "query-all", + "label": "Admin only - only accessible by the admin", + }, + ] + } + > + + Query access level + , + "compressed": undefined, + } + } + > +
+ + + + Query access level + + + + +
+ +
+ +
+ + +
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/__snapshots__/configure_amazon_s3_data_source.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/__snapshots__/configure_amazon_s3_data_source.test.tsx.snap new file mode 100644 index 000000000000..c90faa94daf8 --- /dev/null +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/amazon_s3/__snapshots__/configure_amazon_s3_data_source.test.tsx.snap @@ -0,0 +1,1253 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ConfigureS3DatasourcePanel renders correctly 1`] = ` + + + + +
+ +
+ +

+ Configure Amazon S3 data source +

+
+ +
+ + +
+
+ + + Setup Amazon EMR as execution engine first + +
+ +
+ +
+ +
+ +
+ Connect to Amazon S3 via AWS Glue Data Catalog with Amazon EMR as an execution engine. +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+

+ Data source details +

+
+
+ +
+ + + +
+
+ + + +
+
+ + +
+
+ + + + +
+
+
+
+ +
+ Connection name that OpenSearch Dashboards references. This name should be descriptive and concise. +
+
+
+
+
+
+ +
+
+ + + +
+
+ + +
-

- this is my foo workspace description -

+ + 164 characters left. +
+
+
+
+
+ class="euiFlexItem" + > +

+ Use case +

+
+
+
+
+ +
+
+
+
+
+ +
+
+ + Select an option: Observability, is selected + + +
+ + +
+
+
+
+
+
+
+ You can only choose use cases with more features than the current use case. +
+
+
+
+
+
+
+
+
+

+ Workspace icon color +

+
+
+ The background color of the icon that represents the workspace. +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+
+
+
+
-
+
+
diff --git a/src/plugins/workspace/public/components/workspace_detail/association_data_source_modal.tsx b/src/plugins/workspace/public/components/workspace_detail/association_data_source_modal.tsx new file mode 100644 index 000000000000..999ac80f7ad0 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/association_data_source_modal.tsx @@ -0,0 +1,121 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Fragment, useEffect, useMemo, useState } from 'react'; +import React from 'react'; +import { + EuiText, + EuiModal, + EuiButton, + EuiModalBody, + EuiSelectable, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiSelectableOption, +} from '@elastic/eui'; +import { FormattedMessage } from 'react-intl'; +import { getDataSourcesList } from '../../utils'; +import { DataSource } from '../../../common/types'; +import { SavedObjectsStart } from '../../../../../core/public'; + +export interface AssociationDataSourceModalProps { + savedObjects: SavedObjectsStart; + assignedDataSources: DataSource[]; + closeModal: () => void; + handleAssignDataSources: (dataSources: DataSource[]) => Promise; +} + +export const AssociationDataSourceModal = ({ + closeModal, + savedObjects, + assignedDataSources, + handleAssignDataSources, +}: AssociationDataSourceModalProps) => { + const [options, setOptions] = useState([]); + const [allDataSources, setAllDataSources] = useState([]); + + useEffect(() => { + getDataSourcesList(savedObjects.client, ['*']).then((result) => { + const filteredDataSources = result.filter( + ({ id }: DataSource) => !assignedDataSources.some((ds) => ds.id === id) + ); + setAllDataSources(filteredDataSources); + setOptions( + filteredDataSources.map((dataSource) => ({ + label: dataSource.title, + key: dataSource.id, + })) + ); + }); + }, [assignedDataSources, savedObjects]); + + const selectedDataSources = useMemo(() => { + const selectedIds = options + .filter((option: EuiSelectableOption) => option.checked) + .map((option: EuiSelectableOption) => option.key); + + return allDataSources.filter((ds) => selectedIds.includes(ds.id)); + }, [options, allDataSources]); + + return ( + + + +

+ +

+
+
+ + + + + setOptions(newOptions)} + > + {(list, search) => ( + + {search} + {list} + + )} + + + + + + + + handleAssignDataSources(selectedDataSources)} + isDisabled={!selectedDataSources || selectedDataSources.length === 0} + fill + > + + + +
+ ); +}; diff --git a/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx b/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx new file mode 100644 index 000000000000..ed6ce46965ac --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx @@ -0,0 +1,224 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useMemo, useState } from 'react'; +import { + EuiSpacer, + EuiButton, + EuiFlexItem, + EuiFlexGroup, + EuiFieldSearch, + EuiInMemoryTable, + EuiBasicTableColumn, + EuiTableSelectionType, + EuiTableActionsColumnType, + EuiConfirmModal, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { CoreStart, WorkspaceObject } from '../../../../../core/public'; +import { DataSource } from '../../../common/types'; +import { WorkspaceClient } from '../../workspace_client'; +import { convertPermissionSettingsToPermissions, useWorkspaceFormContext } from '../workspace_form'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; + +interface OpenSearchConnectionTableProps { + assignedDataSources: DataSource[]; + isDashboardAdmin: boolean; + currentWorkspace: WorkspaceObject; + setIsLoading: React.Dispatch>; +} + +export const OpenSearchConnectionTable = ({ + assignedDataSources, + isDashboardAdmin, + currentWorkspace, + setIsLoading, +}: OpenSearchConnectionTableProps) => { + const { + services: { notifications, workspaceClient }, + } = useOpenSearchDashboards<{ CoreStart: CoreStart; workspaceClient: WorkspaceClient }>(); + const { formData, setSelectedDataSources } = useWorkspaceFormContext(); + const [searchTerm, setSearchTerm] = useState(''); + const [SelectedItems, setSelectedItems] = useState([]); + const [assignItems, setAssignItems] = useState([]); + const [modalVisible, setModalVisible] = useState(false); + + const filteredDataSources = useMemo( + () => + assignedDataSources.filter((dataSource) => + dataSource.title.toLowerCase().includes(searchTerm.toLowerCase()) + ), + [searchTerm, assignedDataSources] + ); + + const onSelectionChange = (selectedItems: DataSource[]) => { + setSelectedItems(selectedItems); + setAssignItems(selectedItems); + }; + + const handleUnassignDataSources = async (dataSources: DataSource[]) => { + try { + setIsLoading(true); + setModalVisible(false); + const { permissionSettings, selectedDataSources, useCase, ...attributes } = formData; + const savedDataSources = (selectedDataSources ?? [])?.filter( + ({ id }: DataSource) => !dataSources.some((item) => item.id === id) + ); + + const result = await workspaceClient.update(currentWorkspace.id, attributes, { + dataSources: savedDataSources.map(({ id }: DataSource) => id), + permissions: convertPermissionSettingsToPermissions(permissionSettings), + }); + if (result?.success) { + notifications?.toasts.addSuccess({ + title: i18n.translate('workspace.detail.dataSources.unassign.success', { + defaultMessage: 'Remove associated OpenSearch connections successfully', + }), + }); + setSelectedDataSources(savedDataSources); + } else { + throw new Error( + result?.error ? result?.error : 'Remove associated OpenSearch connections failed' + ); + } + } catch (error) { + notifications?.toasts.addDanger({ + title: i18n.translate('workspace.detail.dataSources.unassign.failed', { + defaultMessage: 'Failed to remove associated OpenSearch connections', + }), + text: error instanceof Error ? error.message : JSON.stringify(error), + }); + } finally { + setIsLoading(false); + } + }; + + const columns: Array> = [ + { + field: 'title', + name: i18n.translate('workspace.detail.dataSources.table.title', { + defaultMessage: 'Title', + }), + truncateText: true, + }, + { + field: 'dataSourceEngineType', + name: i18n.translate('workspace.detail.dataSources.table.type', { + defaultMessage: 'Type', + }), + truncateText: true, + }, + { + field: 'description', + name: i18n.translate('workspace.detail.dataSources.table.description', { + defaultMessage: 'Description', + }), + truncateText: true, + }, + ...(isDashboardAdmin + ? [ + { + name: i18n.translate('workspace.detail.dataSources.table.actions', { + defaultMessage: 'Actions', + }), + actions: [ + { + name: i18n.translate('workspace.detail.dataSources.table.actions.remove.name', { + defaultMessage: 'Remove association', + }), + isPrimary: true, + description: i18n.translate( + 'workspace.detail.dataSources.table.actions.remove.description', + { + defaultMessage: 'Remove association', + } + ), + icon: 'unlink', + type: 'icon', + onClick: (item: DataSource) => { + setAssignItems([item]); + setModalVisible(true); + }, + 'data-test-subj': 'workspace-detail-dataSources-table-actions-remove', + }, + ], + } as EuiTableActionsColumnType, + ] + : []), + ]; + + const selection: EuiTableSelectionType = { + selectable: () => isDashboardAdmin, + onSelectionChange, + }; + + const handleSearch = (e: React.ChangeEvent) => { + setSearchTerm(e.target.value); + }; + return ( + <> + + {SelectedItems.length > 0 && !modalVisible && ( + + setModalVisible(true)} + data-test-subj="workspace-detail-dataSources-table-bulkRemove" + > + {i18n.translate('workspace.detail.dataSources.table.remove.button', { + defaultMessage: 'Remove {numberOfSelect} association(s)', + values: { numberOfSelect: SelectedItems.length }, + })} + + + )} + + + + + + + + {modalVisible && ( + { + setModalVisible(false); + }} + onConfirm={() => { + handleUnassignDataSources(assignItems); + }} + cancelButtonText={i18n.translate('workspace.detail.dataSources.modal.cancelButton', { + defaultMessage: 'Cancel', + })} + confirmButtonText={i18n.translate('workspace.detail.dataSources.Modal.confirmButton', { + defaultMessage: 'Remove connections', + })} + buttonColor="danger" + defaultFocusedButton="confirm" + /> + )} + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.test.tsx b/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.test.tsx new file mode 100644 index 000000000000..6a81482096ec --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.test.tsx @@ -0,0 +1,304 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import React from 'react'; +import { coreMock } from '../../../../../core/public/mocks'; +import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; +import { WorkspaceFormProvider, WorkspaceOperationType } from '../workspace_form'; +import { SelectDataSourceDetailPanel } from './select_data_source_panel'; +import * as utils from '../../utils'; +import { IntlProvider } from 'react-intl'; + +const mockCoreStart = coreMock.createStart(); + +const workspaceObject = { + id: 'foo_id', + name: 'foo', + description: 'this is my foo workspace description', + features: ['use-case-observability', 'workspace_detail'], +}; + +const dataSources = [ + { + id: 'ds-1', + title: 'ds-1-title', + description: 'ds-1-description', + }, + { + id: 'ds-2', + title: 'ds-2-title', + description: 'ds-2-description', + }, +]; +jest.spyOn(utils, 'getDataSourcesList').mockResolvedValue(dataSources); + +const defaultValues = { + id: workspaceObject.id, + name: workspaceObject.name, + features: workspaceObject.features, + selectedDataSources: [dataSources[0]], +}; + +const defaultProps = { + savedObjects: {}, + assignedDataSources: [], + detailTitle: 'Data Sources', + isDashboardAdmin: true, + currentWorkspace: workspaceObject, +}; + +const notificationToastsAddSuccess = jest.fn(); +const notificationToastsAddDanger = jest.fn(); + +const success = jest.fn().mockResolvedValue({ + success: true, +}); +const failed = jest.fn().mockResolvedValue({}); + +const WorkspaceDetailPage = (props: any) => { + const { Provider } = createOpenSearchDashboardsReactContext({ + ...mockCoreStart, + ...{ + notifications: { + ...mockCoreStart.notifications, + toasts: { + ...mockCoreStart.notifications.toasts, + addDanger: notificationToastsAddDanger, + addSuccess: notificationToastsAddSuccess, + }, + }, + workspaceClient: { + update: props.action, + }, + }, + }); + + return ( + + + + + + + + ); +}; + +describe('WorkspaceDetail', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('renders "No associated data sources" message when no data sources are assigned', () => { + const { getByText } = render(WorkspaceDetailPage(defaultProps)); + expect(getByText('No associated data sources')).toBeInTheDocument(); + expect( + getByText('No OpenSearch connections are available in this workspace.') + ).toBeInTheDocument(); + }); + + it('should not show Association OpenSearch Connections button when user is not OSD admin', () => { + const { getByText, queryByText } = render( + WorkspaceDetailPage({ + ...defaultProps, + isDashboardAdmin: false, + }) + ); + expect( + getByText('Contact your administrator to associate data sources with the workspace.') + ).toBeInTheDocument(); + expect(queryByText('Association OpenSearch Connections')).toBeNull(); + }); + + it('should click on Association OpenSearch Connections button', async () => { + Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { + configurable: true, + value: 600, + }); + Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { + configurable: true, + value: 600, + }); + const { getByText } = render( + WorkspaceDetailPage({ ...defaultProps, assignedDataSources: [dataSources[0]] }) + ); + expect(getByText('Association OpenSearch Connections')).toBeInTheDocument(); + + fireEvent.click(getByText('Association OpenSearch Connections')); + await waitFor(() => { + expect( + getByText('Add OpenSearch connections that will be available in the workspace.') + ).toBeInTheDocument(); + expect(getByText('Close')).toBeInTheDocument(); + expect(getByText('Save changes')).toBeInTheDocument(); + expect(getByText('ds-2-title')).toBeInTheDocument(); + }); + fireEvent.click(getByText('Close')); + }); + + it('Association OpenSearch connections successfully', async () => { + Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { + configurable: true, + value: 600, + }); + Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { + configurable: true, + value: 600, + }); + const { getByText } = render( + WorkspaceDetailPage({ + ...defaultProps, + assignedDataSources: [dataSources[0]], + action: success, + }) + ); + expect(getByText('Association OpenSearch Connections')).toBeInTheDocument(); + + fireEvent.click(getByText('Association OpenSearch Connections')); + await waitFor(() => { + expect( + getByText('Add OpenSearch connections that will be available in the workspace.') + ).toBeInTheDocument(); + expect(getByText('Close')).toBeInTheDocument(); + expect(getByText('Save changes')).toBeInTheDocument(); + expect(getByText('ds-2-title')).toBeInTheDocument(); + }); + fireEvent.click(getByText('ds-2-title')); + fireEvent.click(getByText('Save changes')); + await waitFor(() => { + expect(notificationToastsAddSuccess).toHaveBeenCalled(); + }); + }); + + it('Association OpenSearch connections failed', async () => { + Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { + configurable: true, + value: 600, + }); + Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { + configurable: true, + value: 600, + }); + const { getByText } = render( + WorkspaceDetailPage({ + ...defaultProps, + assignedDataSources: [dataSources[0]], + action: failed, + }) + ); + expect(getByText('Association OpenSearch Connections')).toBeInTheDocument(); + + fireEvent.click(getByText('Association OpenSearch Connections')); + await waitFor(() => { + expect( + getByText('Add OpenSearch connections that will be available in the workspace.') + ).toBeInTheDocument(); + expect(getByText('Close')).toBeInTheDocument(); + expect(getByText('Save changes')).toBeInTheDocument(); + expect(getByText('ds-2-title')).toBeInTheDocument(); + }); + fireEvent.click(getByText('ds-2-title')); + fireEvent.click(getByText('Save changes')); + await waitFor(() => { + expect(notificationToastsAddDanger).toHaveBeenCalled(); + }); + }); + + it('Remove OpenSearch connections successfully', async () => { + const { getByText, getByTestId } = render( + WorkspaceDetailPage({ + ...defaultProps, + assignedDataSources: [dataSources[0]], + action: success, + }) + ); + expect(getByText('ds-1-title')).toBeInTheDocument(); + const button = getByTestId('workspace-detail-dataSources-table-actions-remove'); + fireEvent.click(button); + expect(getByText('Remove OpenSearch connections')).toBeInTheDocument(); + fireEvent.click(getByText('Cancel')); + fireEvent.click(button); + fireEvent.click(getByText('Remove connections')); + await waitFor(() => { + expect(notificationToastsAddSuccess).toHaveBeenCalled(); + }); + }); + + it('Remove OpenSearch connections failed', async () => { + const { getByText, getByTestId } = render( + WorkspaceDetailPage({ + ...defaultProps, + assignedDataSources: [dataSources[0]], + action: failed, + }) + ); + expect(getByText('ds-1-title')).toBeInTheDocument(); + const button = getByTestId('workspace-detail-dataSources-table-actions-remove'); + fireEvent.click(button); + fireEvent.click(getByText('Remove connections')); + await waitFor(() => { + expect(notificationToastsAddDanger).toHaveBeenCalled(); + }); + }); + + it('Remove selected OpenSearch connections successfully', async () => { + const { getByText, queryByTestId } = render( + WorkspaceDetailPage({ + ...defaultProps, + assignedDataSources: [dataSources[0]], + action: success, + }) + ); + expect(getByText('ds-1-title')).toBeInTheDocument(); + expect(queryByTestId('workspace-detail-dataSources-table-bulkRemove')).toBeNull(); + const checkbox = screen.getAllByRole('checkbox')[0]; + + // Simulate clicking the checkbox + fireEvent.click(checkbox); + expect(getByText('Remove 1 association(s)')).toBeInTheDocument(); + fireEvent.click(getByText('Remove 1 association(s)')); + fireEvent.click(getByText('Remove connections')); + await waitFor(() => { + expect(notificationToastsAddSuccess).toHaveBeenCalled(); + }); + }); + + it('should handle input in the search box', async () => { + const { getByText, queryByText } = render( + WorkspaceDetailPage({ + ...defaultProps, + assignedDataSources: dataSources, + }) + ); + expect(getByText('ds-1-title')).toBeInTheDocument(); + expect(getByText('ds-2-title')).toBeInTheDocument(); + + const searchInput = screen.getByPlaceholderText('Search'); + // Simulate typing in the search input + fireEvent.change(searchInput, { target: { value: 'ds-1-title' } }); + expect(getByText('ds-1-title')).toBeInTheDocument(); + expect(queryByText('ds-2-title')).toBeNull(); + }); + + it('should not allow user to remove associations when user is not OSD admin', () => { + const { queryByTestId } = render( + WorkspaceDetailPage({ + ...defaultProps, + assignedDataSources: dataSources, + isDashboardAdmin: false, + }) + ); + expect(queryByTestId('workspace-detail-dataSources-table-action-Remove')).toBeNull(); + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.tsx b/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.tsx new file mode 100644 index 000000000000..db4c06fa75f4 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/select_data_source_panel.tsx @@ -0,0 +1,183 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { + EuiText, + EuiTitle, + EuiPanel, + EuiSpacer, + EuiFlexItem, + EuiTextAlign, + EuiFlexGroup, + EuiSmallButton, + EuiHorizontalRule, + EuiLoadingSpinner, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { FormattedMessage } from 'react-intl'; +import { DataSource } from '../../../common/types'; +import { WorkspaceClient } from '../../workspace_client'; +import { OpenSearchConnectionTable } from './opensearch_connections_table'; +import { AssociationDataSourceModal } from './association_data_source_modal'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { CoreStart, SavedObjectsStart, WorkspaceObject } from '../../../../../core/public'; +import { convertPermissionSettingsToPermissions, useWorkspaceFormContext } from '../workspace_form'; + +export interface SelectDataSourcePanelProps { + savedObjects: SavedObjectsStart; + assignedDataSources: DataSource[]; + detailTitle: string; + isDashboardAdmin: boolean; + currentWorkspace: WorkspaceObject; +} + +export const SelectDataSourceDetailPanel = ({ + assignedDataSources, + savedObjects, + detailTitle, + isDashboardAdmin, + currentWorkspace, +}: SelectDataSourcePanelProps) => { + const { + services: { notifications, workspaceClient }, + } = useOpenSearchDashboards<{ CoreStart: CoreStart; workspaceClient: WorkspaceClient }>(); + const { formData, setSelectedDataSources } = useWorkspaceFormContext(); + const [isLoading, setIsLoading] = useState(false); + const [isVisible, setIsVisible] = useState(false); + + const handleAssignDataSources = async (dataSources: DataSource[]) => { + try { + setIsLoading(true); + setIsVisible(false); + const { permissionSettings, selectedDataSources, useCase, ...attributes } = formData; + const savedDataSources: DataSource[] = [...selectedDataSources, ...dataSources]; + + const result = await workspaceClient.update(currentWorkspace.id, attributes, { + dataSources: savedDataSources.map((ds) => { + return ds.id; + }), + permissions: convertPermissionSettingsToPermissions(permissionSettings), + }); + if (result?.success) { + notifications?.toasts.addSuccess({ + title: i18n.translate('workspace.detail.dataSources.assign.success', { + defaultMessage: 'Associate OpenSearch connections successfully', + }), + }); + setSelectedDataSources(savedDataSources); + } else { + throw new Error(result?.error ? result?.error : 'Associate OpenSearch connections failed'); + } + } catch (error) { + notifications?.toasts.addDanger({ + title: i18n.translate('workspace.detail.dataSources.assign.failed', { + defaultMessage: 'Failed to associate OpenSearch connections', + }), + text: error instanceof Error ? error.message : JSON.stringify(error), + }); + } finally { + setIsLoading(false); + } + }; + + const associationButton = ( + setIsVisible(true)} + isLoading={isLoading} + data-test-subj="workspace-detail-dataSources-assign-button" + > + {i18n.translate('workspace.detail.dataSources.assign.button', { + defaultMessage: 'Association OpenSearch Connections', + })} + + ); + + const loadingMessage = ( +
+ + + + + +
+ ); + + const noAssociationMessage = ( + + +

+ +

+
+ + + + + {isDashboardAdmin ? ( + <> + + {associationButton} + + ) : ( + + + + )} +
+ ); + + const renderTableContent = () => { + if (isLoading) { + return loadingMessage; + } + if (assignedDataSources.length === 0) { + return noAssociationMessage; + } + return ( + + ); + }; + + return ( + + + + +

{detailTitle}

+
+
+ {isDashboardAdmin && {associationButton}} +
+ + {renderTableContent()} + {isVisible && ( + setIsVisible(false)} + handleAssignDataSources={handleAssignDataSources} + /> + )} +
+ ); +}; diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_bottom_bar.test.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_bottom_bar.test.tsx new file mode 100644 index 000000000000..2214587d121a --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_bottom_bar.test.tsx @@ -0,0 +1,54 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { WorkspaceBottomBar } from './workspace_bottom_bar'; + +const mockHandleResetForm = jest.fn(); + +const defaultProps = { + formId: 'testForm', + numberOfChanges: 2, + numberOfErrors: 1, + handleResetForm: mockHandleResetForm, +}; + +describe('WorkspaceBottomBar', () => { + test('renders correctly with errors and unsaved changes', () => { + render(); + + expect(screen.getByText('2 Unsaved change(s)')).toBeInTheDocument(); + expect(screen.getByText('2 error(s)')).toBeInTheDocument(); + expect(screen.getByText('Discard changes')).toBeInTheDocument(); + expect(screen.getByText('Save changes')).toBeInTheDocument(); + }); + + test('disables the save button when there are no changes', () => { + render(); + const saveButton = screen.getByRole('button', { name: 'Save changes' }); + expect(saveButton).toBeDisabled(); + }); + + test('calls handleResetForm when discard changes button is clicked', () => { + render(); + fireEvent.click(screen.getByText('Discard changes')); + expect(mockHandleResetForm).toHaveBeenCalled(); + }); + + test('calls handleSubmit when save changes button is clicked', () => { + const handleSubmit = jest.fn(); + render( +
+ + + ); + + fireEvent.click(screen.getByRole('button', { name: 'Save changes' })); + + // Assuming handleSubmit is called during form submission + expect(handleSubmit).toHaveBeenCalled(); + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_bottom_bar.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_bottom_bar.tsx new file mode 100644 index 000000000000..fdc817dc6f80 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_bottom_bar.tsx @@ -0,0 +1,101 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiBottomBar, + EuiSmallButton, + EuiSmallButtonEmpty, + EuiFlexGroup, + EuiFlexItem, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +interface WorkspaceBottomBarProps { + formId: string; + numberOfChanges: number; + numberOfErrors: number; + handleResetForm: () => void; +} + +export const WorkspaceBottomBar = ({ + formId, + numberOfChanges, + numberOfErrors, + handleResetForm, +}: WorkspaceBottomBarProps) => { + const applicationElement = document.querySelector('.app-wrapper'); + const bottomBar = ( + + + + + + {numberOfErrors > 0 && ( + + {i18n.translate('workspace.form.bottomBar.errors', { + defaultMessage: '{numberOfChanges} error(s)', + values: { + numberOfChanges, + }, + })} + + )} + + + {numberOfChanges > 0 && ( + + {i18n.translate('workspace.form.bottomBar.unsavedChanges', { + defaultMessage: '{numberOfChanges} Unsaved change(s)', + values: { + numberOfChanges, + }, + })} + + )} + + + + + + + + {i18n.translate('workspace.form.bottomBar.disCardChanges', { + defaultMessage: 'Discard changes', + })} + + + + + {i18n.translate('workspace.form.bottomBar.saveChanges', { + defaultMessage: 'Save changes', + })} + + + + + + + ); + if (!applicationElement) { + return bottomBar; + } + + return ReactDOM.createPortal(bottomBar, applicationElement); +}; diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx index 2562e7a7591e..cc23f3af8ec8 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.test.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; import React from 'react'; import { BehaviorSubject } from 'rxjs'; import { PublicAppInfo, WorkspaceObject } from 'opensearch-dashboards/public'; @@ -11,6 +11,8 @@ import { coreMock } from '../../../../../core/public/mocks'; import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; import { WORKSPACE_USE_CASES } from '../../../common/constants'; import { WorkspaceDetail } from './workspace_detail'; +import { WorkspaceFormProvider, WorkspaceOperationType } from '../workspace_form'; +import { MemoryRouter } from 'react-router-dom'; // all applications const PublicAPPInfoMap = new Map([ @@ -24,10 +26,40 @@ const workspaceObject = { id: 'foo_id', name: 'foo', description: 'this is my foo workspace description', - features: ['use-case-observability'], + features: ['use-case-observability', 'workspace_detail'], color: '', - icon: '', reserved: false, + permissions: { write: { users: ['user1', 'user2'] } }, +}; + +const defaultValues = { + id: workspaceObject.id, + name: workspaceObject.name, + description: workspaceObject.description, + features: workspaceObject.features, + color: workspaceObject.color, + permissionSettings: [ + { + id: 0, + type: 'user', + userId: 'user1', + modes: ['library_write', 'write'], + }, + { + id: 1, + type: 'user2', + group: '', + modes: ['library_write', 'write'], + }, + ], + selectedDataSources: [ + { + id: 'ds-1', + title: 'ds-1-title', + description: 'ds-1-description', + dataSourceEngineType: 'OpenSearch', + }, + ], }; const createWorkspacesSetupContractMockWithValue = (workspace?: WorkspaceObject) => { @@ -44,8 +76,23 @@ const createWorkspacesSetupContractMockWithValue = (workspace?: WorkspaceObject) }; }; +const deleteFn = jest.fn().mockReturnValue({ + success: true, +}); + const WorkspaceDetailPage = (props: any) => { const workspacesService = props.workspacesService || createWorkspacesSetupContractMockWithValue(); + const values = props.defaultValues || defaultValues; + const permissionEnabled = props.permissionEnabled ?? true; + const dataSourceManagement = + props.dataSourceEnabled !== false + ? { + ui: { + getDataSourceMenu: jest.fn(), + }, + } + : undefined; + const { Provider } = createOpenSearchDashboardsReactContext({ ...mockCoreStart, ...{ @@ -55,8 +102,9 @@ const WorkspaceDetailPage = (props: any) => { capabilities: { ...mockCoreStart.application.capabilities, workspaces: { - permissionEnabled: true, + permissionEnabled, }, + dashboards: { isDashboardAdmin: true }, }, }, workspaces: workspacesService, @@ -67,8 +115,10 @@ const WorkspaceDetailPage = (props: any) => { find: jest.fn().mockResolvedValue({ savedObjects: [], }), + delete: deleteFn, }, }, + dataSourceManagement, }, }); @@ -78,47 +128,155 @@ const WorkspaceDetailPage = (props: any) => { WORKSPACE_USE_CASES.essentials, WORKSPACE_USE_CASES.search, ]); - return ( - - - + + + + + + + ); }; describe('WorkspaceDetail', () => { + let mockHistoryPush: jest.Mock; + let mockLocation: Partial; + beforeEach(() => { + mockHistoryPush = jest.fn(); + mockLocation = { + pathname: '/current-path', + search: '', + hash: '', + }; + + jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory: jest.fn().mockReturnValue({ + push: mockHistoryPush, + location: mockLocation, + }), + useLocation: jest.fn().mockReturnValue(mockLocation), + })); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + it('render workspace detail page normally', async () => { const { container } = render(WorkspaceDetailPage({})); expect(container).toMatchSnapshot(); }); - it('default selected tab is overview', async () => { + it('default selected tab is Details', async () => { const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); render(WorkspaceDetailPage({ workspacesService: workspaceService })); + expect(document.querySelector('#details')).toHaveClass('euiTab-isSelected'); expect(screen.queryByTestId('workspaceTabs')).not.toBeNull(); - expect(document.querySelector('#overview')).toHaveClass('euiTab-isSelected'); }); - it('click on collaborators tab will workspace update page with permission', async () => { + it('click on Collaborators tab when permission control enabled', async () => { + const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); + const { getByText } = render(WorkspaceDetailPage({ workspacesService: workspaceService })); + fireEvent.click(getByText('Collaborators')); + expect(document.querySelector('#collaborators')).toHaveClass('euiTab-isSelected'); + }); + + it('click on Data Sources tab when dataSource enabled', async () => { const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); const { getByText } = render(WorkspaceDetailPage({ workspacesService: workspaceService })); - await act(async () => { - fireEvent.click(getByText('Collaborators')); + fireEvent.click(getByText('Data Sources')); + expect(document.querySelector('#dataSources')).toHaveClass('euiTab-isSelected'); + }); + + it('click on delete button will show delete modal', async () => { + const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); + const { getByText, getByTestId, queryByText } = render( + WorkspaceDetailPage({ workspacesService: workspaceService }) + ); + fireEvent.click(getByText('delete')); + expect(getByText('Delete workspace')).toBeInTheDocument(); + fireEvent.click(getByText('Cancel')); + expect(queryByText('Delete workspace')).toBeNull(); + fireEvent.click(getByText('delete')); + const input = getByTestId('delete-workspace-modal-input'); + fireEvent.change(input, { + target: { value: 'delete' }, + }); + const confirmButton = getByTestId('delete-workspace-modal-confirm'); + fireEvent.click(confirmButton); + }); + + it('click on Collaborators tab when permission control and dataSource disabled', async () => { + const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); + const { queryByText } = render( + WorkspaceDetailPage({ + workspacesService: workspaceService, + permissionEnabled: false, + dataSourceEnabled: false, + }) + ); + expect(queryByText('Collaborators')).toBeNull(); + expect(queryByText('Data Sources')).toBeNull(); + }); + + it('click on tab button will show navigate modal when number of changes > 1', async () => { + const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); + const { getByText, getByTestId, queryByText } = render( + WorkspaceDetailPage({ workspacesService: workspaceService }) + ); + fireEvent.click(getByText('Edit')); + expect(getByTestId('workspaceForm-workspaceDetails-discardChanges')).toBeInTheDocument(); + const input = getByTestId('workspaceForm-workspaceDetails-nameInputText'); + fireEvent.change(input, { + target: { value: 'newName' }, }); + fireEvent.click(getByText('Collaborators')); + expect(getByText('Any unsaved changes will be lost.')).toBeInTheDocument(); + fireEvent.click(getByText('Cancel')); + expect(queryByText('Any unsaved changes will be lost.')).toBeNull(); + fireEvent.click(getByText('Collaborators')); + const button = getByText('Navigate away'); + fireEvent.click(button); expect(document.querySelector('#collaborators')).toHaveClass('euiTab-isSelected'); - await waitFor(() => { - expect(screen.queryByText('Manage access and permissions')).not.toBeNull(); + }); + + it('click on badge button will navigate to Collaborators tab when number of changes > 0', async () => { + const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); + const { getByText, getByTestId } = render( + WorkspaceDetailPage({ workspacesService: workspaceService }) + ); + expect(getByText('+1 more')).toBeInTheDocument(); + + fireEvent.click(getByText('Edit')); + expect(getByTestId('workspaceForm-workspaceDetails-discardChanges')).toBeInTheDocument(); + const input = getByTestId('workspaceForm-workspaceDetails-nameInputText'); + fireEvent.change(input, { + target: { value: 'newName' }, }); + + fireEvent.click(getByText('+1 more')); + expect(getByText('Any unsaved changes will be lost.')).toBeInTheDocument(); + + fireEvent.click(getByText('Navigate away')); + expect(document.querySelector('#collaborators')).toHaveClass('euiTab-isSelected'); }); - it('click on settings tab will show workspace update page', async () => { + it('click on badge button will navigate to Collaborators tab when number of changes = 0', async () => { const workspaceService = createWorkspacesSetupContractMockWithValue(workspaceObject); const { getByText } = render(WorkspaceDetailPage({ workspacesService: workspaceService })); - fireEvent.click(getByText('Settings')); - expect(document.querySelector('#settings')).toHaveClass('euiTab-isSelected'); - await waitFor(() => { - expect(screen.queryByText('Enter details')).not.toBeNull(); - }); + expect(getByText('+1 more')).toBeInTheDocument(); + fireEvent.click(getByText('+1 more')); + expect(document.querySelector('#collaborators')).toHaveClass('euiTab-isSelected'); }); it('will not render xss content', async () => { diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx index 59098a5e7219..a95756947424 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx @@ -3,18 +3,37 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React from 'react'; -import { EuiPage, EuiPageBody, EuiTabbedContent } from '@elastic/eui'; - -import { useObservable } from 'react-use'; +import React, { useEffect, useState } from 'react'; +import { + EuiPage, + EuiText, + EuiSpacer, + EuiFlexItem, + EuiPageBody, + EuiFlexGroup, + EuiPageHeader, + EuiPageContent, + EuiSmallButton, + EuiConfirmModal, + EuiTabbedContent, +} from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { CoreStart } from 'opensearch-dashboards/public'; -import { BehaviorSubject } from 'rxjs'; -import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { useObservable } from 'react-use'; +import { BehaviorSubject, of } from 'rxjs'; +import { useHistory, useLocation } from 'react-router-dom'; import { WorkspaceUseCase } from '../../types'; -import { WorkspaceDetailContent } from './workspace_detail_content'; -import { WorkspaceUpdater } from './workspace_updater'; -import { DetailTab } from '../workspace_form/constants'; +import { WorkspaceDetailForm, useWorkspaceFormContext } from '../workspace_form'; +import { WorkspaceDetailPanel } from './workspace_detail_panel'; +import { DeleteWorkspaceModal } from '../delete_workspace_modal'; +import { WORKSPACE_LIST_APP_ID } from '../../../common/constants'; +import { cleanWorkspaceId } from '../../../../../core/public/utils'; +import { DetailTab, DetailTabTitles, WorkspaceOperationType } from '../workspace_form/constants'; +import { CoreStart, WorkspaceAttribute } from '../../../../../core/public'; +import { getFirstUseCaseOfFeatureConfigs, getUseCaseUrl } from '../../utils'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; +import { SelectDataSourceDetailPanel } from './select_data_source_panel'; +import { WorkspaceBottomBar } from './workspace_bottom_bar'; export interface WorkspaceDetailProps { registeredUseCases$: BehaviorSubject; @@ -22,67 +41,203 @@ export interface WorkspaceDetailProps { export const WorkspaceDetail = (props: WorkspaceDetailProps) => { const { - services: { workspaces, application }, - } = useOpenSearchDashboards(); + services: { workspaces, application, http, savedObjects, dataSourceManagement, uiSettings }, + } = useOpenSearchDashboards<{ + CoreStart: CoreStart; + dataSourceManagement?: DataSourceManagementPluginSetup; + }>(); + + const { + formData, + isEditing, + formId, + numberOfErrors, + handleResetForm, + numberOfChanges, + setIsEditing, + } = useWorkspaceFormContext(); + const [deletedWorkspace, setDeletedWorkspace] = useState(null); + const [selectedTabId, setSelectedTabId] = useState(DetailTab.Details); + const [modalVisible, setModalVisible] = useState(false); + const [tabId, setTabId] = useState(DetailTab.Details); - const currentWorkspace = useObservable(workspaces.currentWorkspace$); + const availableUseCases = useObservable(props.registeredUseCases$, []); + const isDashboardAdmin = !!application?.capabilities?.dashboards?.isDashboardAdmin; + const currentWorkspace = useObservable(workspaces ? workspaces.currentWorkspace$ : of(null)); const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; + const currentUseCase = availableUseCases.find( + (useCase) => useCase.id === getFirstUseCaseOfFeatureConfigs(currentWorkspace?.features ?? []) + ); + const history = useHistory(); + const location = useLocation(); + + useEffect(() => { + const params = new URLSearchParams(location.search); + const tab = params.get('tab'); + if (tab) { + setSelectedTabId(tab); + } + }, [location.search]); - if (!currentWorkspace) { + if (!currentWorkspace || !application || !http || !savedObjects || !uiSettings) { return null; } + const useCaseUrl = getUseCaseUrl(currentUseCase, currentWorkspace, application, http); + + const handleTabClick = (tab: any) => { + if (numberOfChanges > 0) { + setTabId(tab.id); + setModalVisible(true); + return; + } + history.push(`?tab=${tab.id}`); + setIsEditing(false); + setSelectedTabId(tab.id); + }; + + const handleBadgeClick = () => { + if (selectedTabId !== DetailTab.Collaborators && numberOfChanges > 0) { + setTabId(DetailTab.Collaborators); + setModalVisible(true); + return; + } + history.push(`?tab=${DetailTab.Collaborators}`); + setSelectedTabId(DetailTab.Collaborators); + }; + + const createDetailTab = (id: DetailTab, detailTitle: string) => ({ + id, + name: detailTitle, + content: ( + + ), + }); + const detailTabs = [ - { - id: DetailTab.Overview, - name: i18n.translate('workspace.overview.tabTitle', { - defaultMessage: 'Overview', - }), - content: , - }, - { - id: DetailTab.Settings, - name: i18n.translate('workspace.overview.setting.tabTitle', { - defaultMessage: 'Settings', - }), - content: ( - - ), - }, - ...(isPermissionEnabled + createDetailTab(DetailTab.Details, DetailTabTitles.details), + ...(dataSourceManagement ? [ { - id: DetailTab.Collaborators, - name: i18n.translate('workspace.overview.collaborators.tabTitle', { - defaultMessage: 'Collaborators', - }), + id: DetailTab.DataSources, + name: DetailTabTitles.dataSources, content: ( - ), }, ] : []), + ...(isPermissionEnabled + ? [createDetailTab(DetailTab.Collaborators, DetailTabTitles.collaborators)] + : []), ]; + const deleteButton = ( + setDeletedWorkspace(currentWorkspace)} + > + {i18n.translate('workspace.detail.delete', { + defaultMessage: 'delete', + })} + + ); + return ( <> - + + + + {currentWorkspace.description} + + + + + + tab.id === selectedTabId)]} + onTabClick={handleTabClick} size="s" /> + {deletedWorkspace && ( + setDeletedWorkspace(null)} + onDeleteSuccess={() => { + window.setTimeout(() => { + window.location.assign( + cleanWorkspaceId( + application.getUrlForApp(WORKSPACE_LIST_APP_ID, { + absolute: false, + }) + ) + ); + }, 1000); + }} + /> + )} + {modalVisible && ( + setModalVisible(false)} + onConfirm={() => { + handleResetForm(); + setModalVisible(false); + history.push(`?tab=${tabId}`); + setSelectedTabId(tabId); + }} + cancelButtonText={i18n.translate('workspace.form.cancelButtonText', { + defaultMessage: 'Cancel', + })} + confirmButtonText={i18n.translate('workspace.form.confirmButtonText', { + defaultMessage: 'Navigate away', + })} + buttonColor="danger" + defaultFocusedButton="confirm" + > + {i18n.translate('workspace.form.cancelModal.body', { + defaultMessage: 'Any unsaved changes will be lost.', + })} + + )} + {isEditing && ( + + )} ); }; diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_content.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_content.tsx deleted file mode 100644 index 3e3010e4143d..000000000000 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_content.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiFlexItem, - EuiCard, - EuiFlexGroup, - EuiPage, - EuiPageContent, - EuiPageBody, - EuiSpacer, -} from '@elastic/eui'; -import React from 'react'; -import { useObservable } from 'react-use'; -import { of } from 'rxjs'; -import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; - -export const WorkspaceDetailContent = () => { - const { - services: { workspaces }, - } = useOpenSearchDashboards(); - - const currentWorkspace = useObservable(workspaces ? workspaces.currentWorkspace$ : of(null)); - - return ( - - - - - - - - - - - - - - ); -}; diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx new file mode 100644 index 000000000000..1f426743ac17 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx @@ -0,0 +1,140 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { + EuiLink, + EuiText, + EuiCopy, + EuiBadge, + EuiFlexItem, + EuiFlexGroup, + EuiButtonIcon, + EuiColorPickerSwatch, +} from '@elastic/eui'; +import moment from 'moment'; +import { i18n } from '@osd/i18n'; +import { WorkspaceUseCase } from '../../types'; +import { WorkspaceObject } from '../../../../../core/public'; +import { WorkspaceAttributeWithPermission } from '../../../../../core/types'; + +const detailUseCase = i18n.translate('workspace.detail.useCase', { + defaultMessage: 'Use case', +}); + +const detailOwner = i18n.translate('workspace.detail.owner', { + defaultMessage: 'Owner', +}); + +const detailLastUpdated = i18n.translate('workspace.detail.lastUpdated', { + defaultMessage: 'Last updated', +}); + +const detailID = i18n.translate('workspace.detail.id', { + defaultMessage: 'ID', +}); + +const workspaceOverview = i18n.translate('workspace.detail.workspaceOverview', { + defaultMessage: 'Workspace overview', +}); + +const overview = i18n.translate('workspace.detail.overview', { + defaultMessage: 'Overview', +}); + +function getOwners(currentWorkspace: WorkspaceAttributeWithPermission) { + const { groups = [], users = [] } = currentWorkspace.permissions!.write; + return [...groups, ...users]; +} + +interface WorkspaceDetailPanelProps { + useCaseUrl: string; + handleBadgeClick: () => void; + currentUseCase: WorkspaceUseCase | undefined; + currentWorkspace: WorkspaceObject; + dateFormat: string; +} +export const WorkspaceDetailPanel = ({ + useCaseUrl, + currentUseCase, + handleBadgeClick, + currentWorkspace, + dateFormat, +}: WorkspaceDetailPanelProps) => { + const owners = getOwners(currentWorkspace); + const formatDate = (lastUpdatedTime: string) => { + return moment(lastUpdatedTime).format(dateFormat); + }; + + return ( + + + +

{detailUseCase}

+

+ + {currentUseCase?.title} +

+
+
+ + +

{detailOwner}

+

+ {owners?.at(0)}   + {owners && owners.length > 1 && ( + + +{owners?.length - 1} more + + )} +

+
+
+ + +

{detailLastUpdated}

+

{formatDate(currentWorkspace.lastUpdatedTime || '')}

+
+
+ + +

{detailID}

+

+ {currentWorkspace.id} + + {(copy) => ( + + )} + +

+
+
+ + +

{workspaceOverview}

+

+ + {overview} + +

+
+
+
+ ); +}; diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx deleted file mode 100644 index e2ecbd0a32cd..000000000000 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_updater.test.tsx +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { PublicAppInfo, WorkspaceObject } from 'opensearch-dashboards/public'; -import { fireEvent, render, waitFor, screen, act } from '@testing-library/react'; -import { BehaviorSubject } from 'rxjs'; - -import { coreMock, workspacesServiceMock } from '../../../../../core/public/mocks'; -import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; -import { DetailTab } from '../workspace_form/constants'; -import { WORKSPACE_USE_CASES } from '../../../common/constants'; -import { - WorkspaceUpdater as WorkspaceUpdaterComponent, - WorkspaceUpdaterProps, -} from './workspace_updater'; - -const workspaceClientUpdate = jest.fn().mockReturnValue({ result: true, success: true }); - -const navigateToApp = jest.fn(); -const notificationToastsAddSuccess = jest.fn(); -const notificationToastsAddDanger = jest.fn(); -const PublicAPPInfoMap = new Map([ - ['data-explorer', { id: 'data-explorer', title: 'Data Explorer' }], - ['dashboards', { id: 'dashboards', title: 'Dashboards' }], -]); -const createWorkspacesSetupContractMockWithValue = () => { - const currentWorkspaceId$ = new BehaviorSubject('workspaceId'); - const currentWorkspace = { - id: 'workspaceId', - name: 'test1', - description: 'test1', - features: ['use-case-observability'], - reserved: false, - permissions: { - library_write: { - users: ['foo'], - }, - write: { - users: ['foo'], - }, - }, - }; - const workspaceList$ = new BehaviorSubject([currentWorkspace]); - const currentWorkspace$ = new BehaviorSubject(currentWorkspace); - const initialized$ = new BehaviorSubject(false); - return { - currentWorkspaceId$, - workspaceList$, - currentWorkspace$, - initialized$, - }; -}; - -const dataSourcesList = [ - { - id: 'id1', - title: 'ds1', // This is used for mocking saved object function - get: () => { - return 'ds1'; - }, - }, - { - id: 'id2', - title: 'ds2', - get: () => { - return 'ds2'; - }, - }, -]; - -const mockCoreStart = coreMock.createStart(); - -const renderCompleted = () => expect(screen.queryByText('Enter details')).not.toBeNull(); - -const WorkspaceUpdater = ( - props: Partial & { - workspacesService?: ReturnType; - } -) => { - const workspacesService = props.workspacesService || createWorkspacesSetupContractMockWithValue(); - const { Provider } = createOpenSearchDashboardsReactContext({ - ...mockCoreStart, - ...{ - application: { - ...mockCoreStart.application, - capabilities: { - ...mockCoreStart.application.capabilities, - workspaces: { - permissionEnabled: true, - }, - dashboards: { - isDashboardAdmin: true, - }, - }, - navigateToApp, - getUrlForApp: jest.fn(() => '/app/workspace_detail'), - applications$: new BehaviorSubject>(PublicAPPInfoMap as any), - }, - workspaces: workspacesService, - notifications: { - ...mockCoreStart.notifications, - toasts: { - ...mockCoreStart.notifications.toasts, - addDanger: notificationToastsAddDanger, - addSuccess: notificationToastsAddSuccess, - }, - }, - workspaceClient: { - ...mockCoreStart.workspaces, - update: workspaceClientUpdate, - }, - savedObjects: { - ...mockCoreStart.savedObjects, - client: { - ...mockCoreStart.savedObjects.client, - find: jest.fn().mockResolvedValue({ - savedObjects: dataSourcesList, - }), - }, - }, - dataSourceManagement: {}, - }, - }); - const registeredUseCases$ = new BehaviorSubject([ - WORKSPACE_USE_CASES.observability, - WORKSPACE_USE_CASES['security-analytics'], - WORKSPACE_USE_CASES.essentials, - WORKSPACE_USE_CASES.search, - ]); - - return ( - - - - ); -}; - -function clearMockedFunctions() { - workspaceClientUpdate.mockClear(); - notificationToastsAddDanger.mockClear(); - notificationToastsAddSuccess.mockClear(); -} - -describe('WorkspaceUpdater', () => { - beforeEach(() => clearMockedFunctions()); - const { location } = window; - const setHrefSpy = jest.fn((href) => href); - - beforeAll(() => { - if (window.location) { - // @ts-ignore - delete window.location; - } - window.location = {} as Location; - Object.defineProperty(window.location, 'href', { - get: () => 'http://localhost/', - set: setHrefSpy, - }); - }); - - afterAll(() => { - window.location = location; - }); - - it('cannot render when the name of the current workspace is empty', async () => { - const mockedWorkspacesService = workspacesServiceMock.createSetupContract(); - const { container } = render( - - ); - expect(container).toMatchInlineSnapshot(`
`); - }); - - it('cannot update workspace with invalid name', async () => { - const { getByTestId } = render(); - - await waitFor(renderCompleted); - - const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); - fireEvent.input(nameInput, { - target: { value: '~' }, - }); - expect(workspaceClientUpdate).not.toHaveBeenCalled(); - }); - - it('cancel update workspace', async () => { - const { findByText, getByTestId } = render(); - await waitFor(renderCompleted); - - fireEvent.click(getByTestId('workspaceForm-bottomBar-cancelButton')); - await findByText('Discard changes?'); - fireEvent.click(getByTestId('confirmModalConfirmButton')); - expect(navigateToApp).toHaveBeenCalled(); - }); - - it('update workspace successfully', async () => { - const { getByTestId, getAllByLabelText } = render( - - ); - await waitFor(renderCompleted); - - const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); - fireEvent.input(nameInput, { - target: { value: 'test workspace name' }, - }); - - const descriptionInput = getByTestId('workspaceForm-workspaceDetails-descriptionInputText'); - fireEvent.input(descriptionInput, { - target: { value: 'test workspace description' }, - }); - const colorSelector = getByTestId( - 'euiColorPickerAnchor workspaceForm-workspaceDetails-colorPicker' - ); - fireEvent.input(colorSelector, { - target: { value: '#000000' }, - }); - - fireEvent.click(getByTestId('workspaceUseCase-observability')); - fireEvent.click(getByTestId('workspaceUseCase-analytics')); - - act(() => { - fireEvent.click(getAllByLabelText('Delete data source')[0]); - }); - - fireEvent.click(getByTestId('workspaceForm-bottomBar-updateButton')); - expect(workspaceClientUpdate).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - name: 'test workspace name', - color: '#000000', - description: 'test workspace description', - features: expect.arrayContaining(['use-case-analytics']), - }), - { - permissions: { - library_write: { - users: ['foo'], - }, - write: { - users: ['foo'], - }, - }, - dataSources: ['id2'], - } - ); - await waitFor(() => { - expect(notificationToastsAddSuccess).toHaveBeenCalled(); - }); - expect(notificationToastsAddDanger).not.toHaveBeenCalled(); - await waitFor(() => { - expect(setHrefSpy).toHaveBeenCalledWith(expect.stringMatching(/workspace_detail$/)); - }); - }); - - it('update workspace permission successfully', async () => { - const { getByTestId, getAllByTestId } = render( - - ); - await waitFor(() => expect(screen.queryByText('Manage access and permissions')).not.toBeNull()); - - const userIdInput = getAllByTestId('comboBoxSearchInput')[0]; - fireEvent.click(userIdInput); - - fireEvent.input(userIdInput, { - target: { value: 'test user id' }, - }); - fireEvent.blur(userIdInput); - - fireEvent.click(getByTestId('workspaceForm-bottomBar-updateButton')); - expect(workspaceClientUpdate).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - name: 'test1', - description: 'test1', - features: expect.arrayContaining(['use-case-observability']), - }), - { - permissions: { - library_write: { - users: ['test user id'], - }, - write: { - users: ['test user id'], - }, - }, - dataSources: ['id1', 'id2'], - } - ); - await waitFor(() => { - expect(notificationToastsAddSuccess).toHaveBeenCalled(); - }); - expect(notificationToastsAddDanger).not.toHaveBeenCalled(); - await waitFor(() => { - expect(setHrefSpy).toHaveBeenCalledWith(expect.stringMatching(/workspace_detail$/)); - }); - }); - - it('should show danger toasts after update workspace failed', async () => { - workspaceClientUpdate.mockReturnValue({ result: false, success: false }); - const { getByTestId } = render(); - await waitFor(renderCompleted); - - const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); - fireEvent.input(nameInput, { - target: { value: 'test workspace name' }, - }); - fireEvent.click(getByTestId('workspaceForm-bottomBar-updateButton')); - expect(workspaceClientUpdate).toHaveBeenCalled(); - await waitFor(() => { - expect(notificationToastsAddDanger).toHaveBeenCalled(); - }); - expect(notificationToastsAddSuccess).not.toHaveBeenCalled(); - }); - - it('should show danger toasts after update workspace threw error', async () => { - workspaceClientUpdate.mockImplementation(() => { - throw new Error('update workspace failed'); - }); - const { getByTestId } = render(); - await waitFor(renderCompleted); - - const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); - fireEvent.input(nameInput, { - target: { value: 'test workspace name' }, - }); - fireEvent.click(getByTestId('workspaceForm-bottomBar-updateButton')); - expect(workspaceClientUpdate).toHaveBeenCalled(); - await waitFor(() => { - expect(notificationToastsAddDanger).toHaveBeenCalled(); - }); - expect(notificationToastsAddSuccess).not.toHaveBeenCalled(); - }); - - it('should show danger toasts when currentWorkspace is missing after click update button', async () => { - const mockedWorkspacesService = workspacesServiceMock.createSetupContract(); - const { getByTestId } = render( - - ); - - await waitFor(renderCompleted); - - const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); - fireEvent.input(nameInput, { - target: { value: 'test workspace name' }, - }); - fireEvent.click(getByTestId('workspaceForm-bottomBar-updateButton')); - mockedWorkspacesService.currentWorkspace$ = new BehaviorSubject(null); - expect(workspaceClientUpdate).toHaveBeenCalled(); - await waitFor(() => { - expect(notificationToastsAddDanger).toHaveBeenCalled(); - }); - expect(notificationToastsAddSuccess).not.toHaveBeenCalled(); - }); -}); diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx deleted file mode 100644 index 9005646fd804..000000000000 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_updater.tsx +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useCallback, useEffect, useState } from 'react'; -import { EuiPage, EuiPageBody, EuiPageContent, EuiSpacer } from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import { useObservable } from 'react-use'; -import { BehaviorSubject, of } from 'rxjs'; -import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants'; -import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; -import { WorkspaceAttributeWithPermission } from '../../../../../core/types'; -import { WorkspaceClient } from '../../workspace_client'; -import { - WorkspaceFormSubmitData, - WorkspaceOperationType, - convertPermissionsToPermissionSettings, - convertPermissionSettingsToPermissions, - WorkspaceDetailForm, -} from '../workspace_form'; -import { getDataSourcesList } from '../../utils'; -import { DataSource } from '../../../common/types'; -import { DetailTab } from '../workspace_form/constants'; -import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; -import { WorkspaceUseCase } from '../../types'; - -export interface WorkspaceUpdaterProps { - registeredUseCases$: BehaviorSubject; - detailTab?: DetailTab; -} - -function getFormDataFromWorkspace( - currentWorkspace: WorkspaceAttributeWithPermission | null | undefined -) { - if (!currentWorkspace) { - return null; - } - return { - ...currentWorkspace, - permissionSettings: currentWorkspace.permissions - ? convertPermissionsToPermissionSettings(currentWorkspace.permissions) - : currentWorkspace.permissions, - }; -} - -type FormDataFromWorkspace = ReturnType & { - selectedDataSources: DataSource[]; -}; - -export const WorkspaceUpdater = (props: WorkspaceUpdaterProps) => { - const { - services: { - application, - workspaces, - notifications, - http, - workspaceClient, - savedObjects, - dataSourceManagement, - }, - } = useOpenSearchDashboards<{ - workspaceClient: WorkspaceClient; - dataSourceManagement?: DataSourceManagementPluginSetup; - }>(); - - const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; - const currentWorkspace = useObservable(workspaces ? workspaces.currentWorkspace$ : of(null)); - const availableUseCases = useObservable(props.registeredUseCases$, []); - const [currentWorkspaceFormData, setCurrentWorkspaceFormData] = useState(); - - const handleWorkspaceFormSubmit = useCallback( - async (data: WorkspaceFormSubmitData) => { - let result; - if (!currentWorkspace) { - notifications?.toasts.addDanger({ - title: i18n.translate('Cannot find current workspace', { - defaultMessage: 'Cannot update workspace', - }), - }); - return; - } - - try { - const { permissionSettings, selectedDataSources, ...attributes } = data; - const selectedDataSourceIds = (selectedDataSources ?? []).map((ds: DataSource) => { - return ds.id; - }); - result = await workspaceClient.update(currentWorkspace.id, attributes, { - dataSources: selectedDataSourceIds, - permissions: convertPermissionSettingsToPermissions(permissionSettings), - }); - if (result?.success) { - notifications?.toasts.addSuccess({ - title: i18n.translate('workspace.update.success', { - defaultMessage: 'Update workspace successfully', - }), - }); - if (application && http) { - // Redirect page after one second, leave one second time to show update successful toast. - window.setTimeout(() => { - window.location.href = formatUrlWithWorkspaceId( - application.getUrlForApp(WORKSPACE_DETAIL_APP_ID, { - absolute: true, - }), - currentWorkspace.id, - http.basePath - ); - }, 1000); - } - return; - } else { - throw new Error(result?.error ? result?.error : 'update workspace failed'); - } - } catch (error) { - notifications?.toasts.addDanger({ - title: i18n.translate('workspace.update.failed', { - defaultMessage: 'Failed to update workspace', - }), - text: error instanceof Error ? error.message : JSON.stringify(error), - }); - return; - } - }, - [notifications?.toasts, currentWorkspace, http, application, workspaceClient] - ); - - useEffect(() => { - const rawFormData = getFormDataFromWorkspace(currentWorkspace); - - if (rawFormData && savedObjects && currentWorkspace) { - getDataSourcesList(savedObjects.client, [currentWorkspace.id]).then((selectedDataSources) => { - setCurrentWorkspaceFormData({ - ...rawFormData, - selectedDataSources, - }); - }); - } - }, [currentWorkspace, savedObjects]); - - if (!currentWorkspaceFormData) { - return null; - } - - return ( - - - - - {application && savedObjects && ( - - )} - - - - ); -}; diff --git a/src/plugins/workspace/public/components/workspace_detail_app.tsx b/src/plugins/workspace/public/components/workspace_detail_app.tsx index 1185f0c66d8f..1347b130575b 100644 --- a/src/plugins/workspace/public/components/workspace_detail_app.tsx +++ b/src/plugins/workspace/public/components/workspace_detail_app.tsx @@ -3,21 +3,63 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useEffect } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { I18nProvider } from '@osd/i18n/react'; import { i18n } from '@osd/i18n'; import { CoreStart } from 'opensearch-dashboards/public'; import { useObservable } from 'react-use'; import { EuiBreadcrumb } from '@elastic/eui'; +import { of } from 'rxjs'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; import { WorkspaceDetail, WorkspaceDetailProps } from './workspace_detail/workspace_detail'; +import { WorkspaceFormProvider } from './workspace_form'; +import { + WorkspaceFormSubmitData, + WorkspaceOperationType, + convertPermissionSettingsToPermissions, + convertPermissionsToPermissionSettings, +} from './workspace_form'; +import { DataSource } from '../../common/types'; +import { WorkspaceClient } from '../workspace_client'; +import { formatUrlWithWorkspaceId } from '../../../../core/public/utils'; +import { WORKSPACE_DETAIL_APP_ID } from '../../common/constants'; +import { getDataSourcesList } from '../utils'; +import { WorkspaceAttributeWithPermission } from '../../../../core/types'; + +function getFormDataFromWorkspace( + currentWorkspace: WorkspaceAttributeWithPermission | null | undefined +) { + if (!currentWorkspace) { + return null; + } + return { + ...currentWorkspace, + permissionSettings: currentWorkspace.permissions + ? convertPermissionsToPermissionSettings(currentWorkspace.permissions) + : currentWorkspace.permissions, + }; +} + +type FormDataFromWorkspace = ReturnType & { + selectedDataSources: DataSource[]; +}; export const WorkspaceDetailApp = (props: WorkspaceDetailProps) => { const { - services: { workspaces, chrome, application }, - } = useOpenSearchDashboards(); - - const currentWorkspace = useObservable(workspaces.currentWorkspace$); + services: { + workspaces, + chrome, + application, + savedObjects, + notifications, + workspaceClient, + http, + }, + } = useOpenSearchDashboards<{ CoreStart: CoreStart; workspaceClient: WorkspaceClient }>(); + const [currentWorkspaceFormData, setCurrentWorkspaceFormData] = useState(); + const currentWorkspace = useObservable(workspaces ? workspaces.currentWorkspace$ : of(null)); + const availableUseCases = useObservable(props.registeredUseCases$, []); + const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; /** * set breadcrumbs to chrome @@ -27,7 +69,7 @@ export const WorkspaceDetailApp = (props: WorkspaceDetailProps) => { { text: 'Home', onClick: () => { - application.navigateToApp('home'); + application?.navigateToApp('home'); }, }, ]; @@ -47,9 +89,93 @@ export const WorkspaceDetailApp = (props: WorkspaceDetailProps) => { chrome?.setBreadcrumbs(breadcrumbs); }, [chrome, currentWorkspace, application]); + useEffect(() => { + const rawFormData = getFormDataFromWorkspace(currentWorkspace); + + if (rawFormData && savedObjects && currentWorkspace) { + getDataSourcesList(savedObjects.client, [currentWorkspace.id]).then((selectedDataSources) => { + setCurrentWorkspaceFormData({ + ...rawFormData, + selectedDataSources, + }); + }); + } + }, [currentWorkspace, savedObjects]); + + const handleWorkspaceFormSubmit = useCallback( + async (data: WorkspaceFormSubmitData) => { + let result; + if (!currentWorkspace) { + notifications?.toasts.addDanger({ + title: i18n.translate('Cannot find current workspace', { + defaultMessage: 'Cannot update workspace', + }), + }); + return; + } + + try { + const { permissionSettings, selectedDataSources, ...attributes } = data; + const selectedDataSourceIds = (selectedDataSources ?? []).map((ds: DataSource) => { + return ds.id; + }); + + result = await workspaceClient.update(currentWorkspace.id, attributes, { + dataSources: selectedDataSourceIds, + permissions: convertPermissionSettingsToPermissions(permissionSettings), + }); + if (result?.success) { + notifications?.toasts.addSuccess({ + title: i18n.translate('workspace.update.success', { + defaultMessage: 'Update workspace successfully', + }), + }); + if (application && http) { + // Redirect page after one second, leave one second time to show update successful toast. + window.setTimeout(() => { + window.location.href = formatUrlWithWorkspaceId( + application.getUrlForApp(WORKSPACE_DETAIL_APP_ID, { + absolute: true, + }), + currentWorkspace.id, + http.basePath + ); + }, 1000); + } + return; + } else { + throw new Error(result?.error ? result?.error : 'update workspace failed'); + } + } catch (error) { + notifications?.toasts.addDanger({ + title: i18n.translate('workspace.update.failed', { + defaultMessage: 'Failed to update workspace', + }), + text: error instanceof Error ? error.message : JSON.stringify(error), + }); + return; + } + }, + [notifications?.toasts, currentWorkspace, http, application, workspaceClient] + ); + + if (!workspaces || !application || !http || !savedObjects || !currentWorkspaceFormData) { + return null; + } + return ( - - - + + + + + ); }; diff --git a/src/plugins/workspace/public/components/workspace_form/constants.ts b/src/plugins/workspace/public/components/workspace_form/constants.ts index 2a2c7142d6f0..a69afeacbbbc 100644 --- a/src/plugins/workspace/public/components/workspace_form/constants.ts +++ b/src/plugins/workspace/public/components/workspace_form/constants.ts @@ -46,11 +46,75 @@ export const selectDataSourceTitle = i18n.translate('workspace.form.selectDataSo }); export const usersAndPermissionsTitle = i18n.translate('workspace.form.usersAndPermissions.title', { - defaultMessage: 'Manage access and permissions', + defaultMessage: 'Workspaces access', }); +export const detailsName = i18n.translate('workspace.form.workspaceDetails.name.label', { + defaultMessage: 'Name', +}); + +export const detailsNameHelpText = i18n.translate('workspace.form.workspaceDetails.name.helpText', { + defaultMessage: + 'Valid characters are a-z, A-Z, 0-9, (), [], _ (underscore), - (hyphen) and (space).', +}); + +export const detailsNamePlaceholder = i18n.translate( + 'workspace.form.workspaceDetails.name.placeholder', + { + defaultMessage: 'Enter a name', + } +); + +export const detailsDescriptionIntroduction = i18n.translate( + 'workspace.form.workspaceDetails.description.introduction', + { + defaultMessage: 'Describe the workspace.', + } +); + +export const detailsDescriptionPlaceholder = i18n.translate( + 'workspace.form.workspaceDetails.description.placeholder', + { + defaultMessage: 'Describe the workspace', + } +); + +export const detailsUseCaseLabel = i18n.translate('workspace.form.workspaceDetails.useCase.label', { + defaultMessage: 'Use case', +}); + +export const detailsUseCaseHelpText = i18n.translate( + 'workspace.form.workspaceDetails.useCase.helpText', + { + defaultMessage: 'You can only choose use cases with more features than the current use case.', + } +); + +export const detailsColorLabel = i18n.translate('workspace.form.workspaceDetails.color.label', { + defaultMessage: 'Workspace icon color', +}); + +export const detailsColorHelpText = i18n.translate( + 'workspace.form.workspaceDetails.color.helpText', + { + defaultMessage: 'The background color of the icon that represents the workspace.', + } +); + export enum DetailTab { - Settings = 'settings', + Details = 'details', + DataSources = 'dataSources', Collaborators = 'collaborators', - Overview = 'overview', } + +export const DetailTabTitles: { [key in DetailTab]: string } = { + [DetailTab.Details]: i18n.translate('workspace.detail.tabTitle.details', { + defaultMessage: 'Details', + }), + [DetailTab.DataSources]: i18n.translate('workspace.detail.tabTitle.dataSources', { + defaultMessage: 'Data Sources', + }), + [DetailTab.Collaborators]: i18n.translate('workspace.detail.tabTitle.collaborators', { + defaultMessage: 'Collaborators', + }), +}; diff --git a/src/plugins/workspace/public/components/workspace_form/index.ts b/src/plugins/workspace/public/components/workspace_form/index.ts index 31addf5a641e..42164ca530e2 100644 --- a/src/plugins/workspace/public/components/workspace_form/index.ts +++ b/src/plugins/workspace/public/components/workspace_form/index.ts @@ -11,3 +11,4 @@ export { convertPermissionsToPermissionSettings, convertPermissionSettingsToPermissions, } from './utils'; +export { WorkspaceFormProvider, useWorkspaceFormContext } from './workspace_form_context'; diff --git a/src/plugins/workspace/public/components/workspace_form/types.ts b/src/plugins/workspace/public/components/workspace_form/types.ts index cbcf7e8ded26..6f0c6a2d2f70 100644 --- a/src/plugins/workspace/public/components/workspace_form/types.ts +++ b/src/plugins/workspace/public/components/workspace_form/types.ts @@ -86,6 +86,7 @@ export interface WorkspaceFormProps { detailTab?: DetailTab; dataSourceManagement?: DataSourceManagementPluginSetup; availableUseCases: WorkspaceUseCase[]; + detailTitle?: string; } export interface WorkspaceDetailedFormProps extends WorkspaceFormProps { diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts index ae9ba5d6a4fa..c946cb35a68c 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts @@ -140,4 +140,23 @@ describe('useWorkspaceForm', () => { }); expect(renderResult.result.current.formData.useCase).toBe('search'); }); + + it('should reset workspace form', () => { + const { renderResult } = setup({ + id: 'test', + name: 'current-workspace-name', + features: ['use-case-observability'], + }); + expect(renderResult.result.current.formData.name).toBe('current-workspace-name'); + + act(() => { + renderResult.result.current.setName('update-workspace-name'); + }); + expect(renderResult.result.current.formData.name).toBe('update-workspace-name'); + + act(() => { + renderResult.result.current.handleResetForm(); + }); + expect(renderResult.result.current.formData.name).toBe('current-workspace-name'); + }); }); diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts index 8b03d246d568..422161bea948 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts @@ -37,6 +37,7 @@ export const useWorkspaceForm = ({ const [description, setDescription] = useState(defaultValues?.description); const [color, setColor] = useState(defaultValues?.color); const defaultValuesRef = useRef(defaultValues); + const [isEditing, setIsEditing] = useState(false); const initialPermissionSettingsRef = useRef( generatePermissionSettingsState(operationType, defaultValues?.permissionSettings) ); @@ -119,7 +120,7 @@ export const useWorkspaceForm = ({ onSubmit?.({ name: currentFormData.name!, description: currentFormData.description, - color: currentFormData.color, + color: currentFormData.color || '#FFFFFF', features: currentFormData.features, permissionSettings: currentFormData.permissionSettings as WorkspacePermissionSetting[], selectedDataSources: currentFormData.selectedDataSources, @@ -132,13 +133,27 @@ export const useWorkspaceForm = ({ setColor(text); }, []); + const handleResetForm = useCallback(() => { + const resetValues = defaultValuesRef.current; + setName(resetValues?.name ?? ''); + setDescription(resetValues?.description); + setColor(resetValues?.color); + setFeatureConfigs(appendDefaultFeatureIds(resetValues?.features ?? [])); + setPermissionSettings(initialPermissionSettingsRef.current); + setFormErrors({}); + setIsEditing(false); + }, []); + return { formId: formIdRef.current, formData, + isEditing, formErrors, + setIsEditing, applications, numberOfErrors, numberOfChanges, + handleResetForm, setName, setDescription, handleFormSubmit, diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_bottom_bar.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_bottom_bar.tsx deleted file mode 100644 index 79819a217de8..000000000000 --- a/src/plugins/workspace/public/components/workspace_form/workspace_bottom_bar.tsx +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - EuiBottomBar, - EuiSmallButton, - EuiSmallButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiText, -} from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import React, { useState, useCallback } from 'react'; -import { ApplicationStart } from 'opensearch-dashboards/public'; -import { WorkspaceCancelModal } from './workspace_cancel_modal'; - -interface WorkspaceBottomBarProps { - formId: string; - application: ApplicationStart; - numberOfChanges: number; -} - -export const WorkspaceBottomBar = ({ - formId, - numberOfChanges, - application, -}: WorkspaceBottomBarProps) => { - const [isCancelModalVisible, setIsCancelModalVisible] = useState(false); - const closeCancelModal = useCallback(() => setIsCancelModalVisible(false), []); - const showCancelModal = useCallback(() => setIsCancelModalVisible(true), []); - - return ( -
- - - - - - - {numberOfChanges > 0 && ( - - {i18n.translate('workspace.form.bottomBar.unsavedChanges', { - defaultMessage: '{numberOfChanges} Unsaved change(s)', - values: { - numberOfChanges, - }, - })} - - )} - - - - - - {i18n.translate('workspace.form.bottomBar.cancel', { - defaultMessage: 'Cancel', - })} - - - - {i18n.translate('workspace.form.bottomBar.saveChanges', { - defaultMessage: 'Save changes', - })} - - - - - - {isCancelModalVisible && ( - - )} -
- ); -}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx index 271f90ca69fa..a8015120d407 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx @@ -4,76 +4,97 @@ */ import './workspace_detail_form.scss'; -import React, { useRef } from 'react'; -import { EuiPanel, EuiSpacer, EuiForm, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import React, { useEffect, useRef, useState } from 'react'; +import { + EuiSpacer, + EuiForm, + EuiFlexGroup, + EuiFlexItem, + EuiTitle, + EuiText, + EuiPanel, + EuiSmallButton, + EuiHorizontalRule, +} from '@elastic/eui'; -import { WorkspaceBottomBar } from './workspace_bottom_bar'; -import { WorkspaceDetailedFormProps } from './types'; -import { useWorkspaceForm } from './use_workspace_form'; -import { WorkspaceUseCase } from './workspace_use_case'; +import { i18n } from '@osd/i18n'; +import { WorkspaceFormProps } from './types'; import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; -import { SelectDataSourcePanel } from './select_data_source_panel'; -import { EnterDetailsPanel } from './workspace_enter_details_panel'; -import { - DetailTab, - WorkspaceOperationType, - selectDataSourceTitle, - usersAndPermissionsTitle, - workspaceDetailsTitle, - workspaceUseCaseTitle, -} from './constants'; -import { WorkspaceCreateActionPanel } from './workspace_create_action_panel'; +import { DetailTab, usersAndPermissionsTitle } from './constants'; import { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; +import { useWorkspaceFormContext } from './workspace_form_context'; +import { WorkspaceDetailFormDetailsProps } from './workspace_detail_form_details'; interface FormGroupProps { - title: string; + title: React.ReactNode; children: React.ReactNode; + describe?: string; } -const FormGroup = ({ title, children }: FormGroupProps) => ( - - - -

{title}

-
-
- {children} -
+const FormGroup = ({ title, children, describe }: FormGroupProps) => ( + <> + + + +

{title}

+
+ + {describe} + +
+ + + {children} + +
+ + ); -export const WorkspaceDetailForm = (props: WorkspaceDetailedFormProps) => { - const { - detailTab, - application, - savedObjects, - defaultValues, - operationType, - availableUseCases, - dataSourceManagement: isDataSourceEnabled, - } = props; +export const WorkspaceDetailForm = (props: WorkspaceFormProps) => { + const { detailTab, detailTitle, defaultValues, availableUseCases } = props; const { formId, formData, + isEditing, formErrors, + setIsEditing, numberOfErrors, numberOfChanges, - setName, - setDescription, + handleResetForm, handleFormSubmit, - handleColorChange, - handleUseCaseChange, setPermissionSettings, - setSelectedDataSources, - } = useWorkspaceForm(props); - - const isDashboardAdmin = application?.capabilities?.dashboards?.isDashboardAdmin ?? false; - + } = useWorkspaceFormContext(); const disabledUserOrGroupInputIdsRef = useRef( defaultValues?.permissionSettings?.map((item) => item.id) ?? [] ); + const [isSaving, setIsSaving] = useState(false); + + // Handle beforeunload event + useEffect(() => { + const handleBeforeUnload = (event: BeforeUnloadEvent) => { + if (!isSaving && isEditing && numberOfChanges > 0) { + event.preventDefault(); + } + }; + + window.addEventListener('beforeunload', handleBeforeUnload); + + return () => { + window.removeEventListener('beforeunload', handleBeforeUnload); + }; + }, [isEditing, isSaving, numberOfChanges]); + return ( - + { + setIsSaving(true); + handleFormSubmit(event); + }} + component="form" + > {numberOfErrors > 0 && ( <> @@ -81,6 +102,38 @@ export const WorkspaceDetailForm = (props: WorkspaceDetailedFormProps) => { )} + + + +

{detailTitle}

+
+
+ + {isEditing ? ( + + {i18n.translate('workspace.detail.button.discardChanges', { + defaultMessage: 'Discard changes', + })} + + ) : ( + setIsEditing((prevIsEditing) => !prevIsEditing)} + data-test-subj="workspaceForm-workspaceDetails-edit" + > + {i18n.translate('workspace.detail.button.edit', { + defaultMessage: 'Edit', + })} + + )} + +
+ + {detailTab === DetailTab.Details && ( + + )} {detailTab === DetailTab.Collaborators && ( { permissionSettings={formData.permissionSettings} disabledUserOrGroupInputIds={disabledUserOrGroupInputIdsRef.current} data-test-subj={`workspaceForm-permissionSettingPanel`} + isEditing={isEditing} /> )} - {detailTab === DetailTab.Settings && ( - <> - - - - - - - - - {isDashboardAdmin && isDataSourceEnabled && ( - - - - )} - - )}
- {operationType === WorkspaceOperationType.Create && ( - - )} - {operationType === WorkspaceOperationType.Update && ( - - )}
); }; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx new file mode 100644 index 000000000000..27de826141b2 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx @@ -0,0 +1,140 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiSuperSelect, + EuiColorPicker, + EuiCompressedFormRow, + EuiDescribedFormGroup, + EuiCompressedTextArea, +} from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { useObservable } from 'react-use'; +import { + detailsName, + detailsColorLabel, + detailsUseCaseLabel, + detailsColorHelpText, + detailsDescriptionPlaceholder, + detailsDescriptionIntroduction, + detailsUseCaseHelpText, +} from './constants'; +import { CoreStart } from '../../../../../core/public'; +import { getFirstUseCaseOfFeatureConfigs } from '../../utils'; +import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; +import { useWorkspaceFormContext } from './workspace_form_context'; +import { WorkspaceUseCase as WorkspaceUseCaseObject } from '../../types'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { WorkspaceNameField } from './fields/workspace_name_field'; +import { WorkspaceDescriptionField } from './fields/workspace_description_field'; + +interface WorkspaceDetailFormDetailsProps { + availableUseCases: Array< + Pick + >; +} + +export const WorkspaceDetailFormDetailsProps = ({ + availableUseCases, +}: WorkspaceDetailFormDetailsProps) => { + const { + setName, + formData, + isEditing, + formErrors, + setDescription, + handleColorChange, + handleUseCaseChange, + } = useWorkspaceFormContext(); + const { + services: { workspaces }, + } = useOpenSearchDashboards(); + const [value, setValue] = useState(formData.useCase); + const currentWorkspace = useObservable(workspaces.currentWorkspace$); + const currentUseCase = getFirstUseCaseOfFeatureConfigs(currentWorkspace?.features ?? []); + + useEffect(() => { + setValue(formData.useCase); + }, [formData.useCase]); + + const options = availableUseCases + .filter((item) => !item.systematic) + .concat(DEFAULT_NAV_GROUPS.all) + .filter(({ id }) => { + // Essential can be changed to other use cases; + // Analytics (all) cannot be changed back to a single use case; + // Other use cases can only be changed to Analytics (all) use case. + return currentUseCase === 'analytics' || id === 'all' || id === currentUseCase; + }) + .map((useCase) => ({ + value: useCase.id, + inputDisplay: useCase.title, + 'data-test-subj': useCase.id, + })); + + return ( + <> + {detailsName}}> + + + + Description - optional + + } + description={detailsDescriptionIntroduction} + > + + + {detailsUseCaseLabel}}> + + { + setValue(id); + handleUseCaseChange(id); + }} + disabled={!isEditing} + readOnly={!isEditing} + /> + + + {detailsColorLabel}} + description={detailsColorHelpText} + > + + + + + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index e8cfd534d922..a968f560fb03 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -6,12 +6,10 @@ import React, { useRef } from 'react'; import { EuiPanel, EuiSpacer, EuiTitle, EuiForm } from '@elastic/eui'; -import { WorkspaceBottomBar } from './workspace_bottom_bar'; import { WorkspaceFormProps } from './types'; import { useWorkspaceForm } from './use_workspace_form'; import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; import { WorkspaceUseCase } from './workspace_use_case'; -import { WorkspaceOperationType } from './constants'; import { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; import { WorkspaceCreateActionPanel } from './workspace_create_action_panel'; import { SelectDataSourcePanel } from './select_data_source_panel'; @@ -28,10 +26,10 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { application, savedObjects, defaultValues, - operationType, permissionEnabled, dataSourceManagement: isDataSourceEnabled, availableUseCases, + operationType, } = props; const { formId, @@ -127,16 +125,7 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { )} - {operationType === WorkspaceOperationType.Create && ( - - )} - {operationType === WorkspaceOperationType.Update && ( - - )} +
); }; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx new file mode 100644 index 000000000000..417921f170d3 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form_context.tsx @@ -0,0 +1,69 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { createContext, useContext, FormEventHandler, ReactNode } from 'react'; +import { EuiColorPickerOutput } from '@elastic/eui/src/components/color_picker/color_picker'; +import { DataSource } from '../../../common/types'; +import { WorkspaceFormProps, WorkspaceFormErrors, WorkspacePermissionSetting } from './types'; +import { PublicAppInfo } from '../../../../../core/public'; +import { useWorkspaceForm } from './use_workspace_form'; + +interface WorkspaceFormContextProps { + formId: string; + setName: React.Dispatch>; + setDescription: React.Dispatch>; + formData: any; + isEditing: boolean; + formErrors: WorkspaceFormErrors; + setIsEditing: React.Dispatch>; + applications: PublicAppInfo[]; + numberOfErrors: number; + numberOfChanges: number; + handleResetForm: () => void; + handleFormSubmit: FormEventHandler; + handleColorChange: (text: string, output: EuiColorPickerOutput) => void; + handleUseCaseChange: (newUseCase: string) => void; + setPermissionSettings: React.Dispatch< + React.SetStateAction< + Array & Partial> + > + >; + setSelectedDataSources: React.Dispatch>; +} + +const initialContextValue: WorkspaceFormContextProps = {} as WorkspaceFormContextProps; +export const WorkspaceFormContext = createContext(initialContextValue); +interface ContextProps extends WorkspaceFormProps { + children: ReactNode; +} + +export const WorkspaceFormProvider = ({ + children, + application, + defaultValues, + operationType, + onSubmit, + permissionEnabled, + savedObjects, + availableUseCases, +}: ContextProps) => { + const workspaceFormContextValue = useWorkspaceForm({ + application, + defaultValues, + operationType, + onSubmit, + permissionEnabled, + savedObjects, + availableUseCases, + }); + + return ( + + {children} + + ); +}; + +export const useWorkspaceFormContext = () => useContext(WorkspaceFormContext); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx index 8827f9bf9b74..40165530c3b2 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx @@ -63,6 +63,7 @@ export interface WorkspacePermissionSettingInputProps { userId?: string; group?: string; modes?: WorkspacePermissionMode[]; + isEditing?: boolean; deletable?: boolean; userOrGroupDisabled: boolean; onGroupOrUserIdChange: ( @@ -84,6 +85,7 @@ export const WorkspacePermissionSettingInput = ({ userId, group, modes, + isEditing = true, deletable = true, userOrGroupDisabled, onDelete, @@ -147,13 +149,13 @@ export const WorkspacePermissionSettingInput = ({ defaultMessage: 'Select a user group', }) } - isDisabled={userOrGroupDisabled} + isDisabled={userOrGroupDisabled || !isEditing} /> - {deletable && ( + {deletable && isEditing && ( & Partial> ) => void; + isEditing?: boolean; } interface UserOrGroupSectionProps extends WorkspacePermissionSettingPanelProps { @@ -44,6 +45,7 @@ const UserOrGroupSection = ({ type, errors, onChange, + isEditing, nextIdGenerator, permissionSettings, disabledUserOrGroupInputIds, @@ -143,24 +145,27 @@ const UserOrGroupSection = ({ onDelete={handleDelete} onGroupOrUserIdChange={handleGroupOrUserIdChange} onPermissionModesChange={handlePermissionModesChange} + isEditing={isEditing} /> ))} - - {type === WorkspacePermissionItemType.User - ? i18n.translate('workspace.form.permissionSettingPanel.addUser', { - defaultMessage: 'Add user', - }) - : i18n.translate('workspace.form.permissionSettingPanel.addUserGroup', { - defaultMessage: 'Add user group', - })} - + {isEditing && ( + + {type === WorkspacePermissionItemType.User + ? i18n.translate('workspace.form.permissionSettingPanel.addUser', { + defaultMessage: 'Add user', + }) + : i18n.translate('workspace.form.permissionSettingPanel.addUserGroup', { + defaultMessage: 'Add user group', + })} + + )}
); }; @@ -170,6 +175,7 @@ export const WorkspacePermissionSettingPanel = ({ onChange, permissionSettings, disabledUserOrGroupInputIds, + isEditing = true, }: WorkspacePermissionSettingPanelProps) => { const userPermissionSettings = useMemo( () => @@ -224,6 +230,7 @@ export const WorkspacePermissionSettingPanel = ({ type={WorkspacePermissionItemType.User} nextIdGenerator={nextIdGenerator} disabledUserOrGroupInputIds={disabledUserOrGroupInputIds} + isEditing={isEditing} />
); diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx index be627abeff31..f0a5f6f7fc8e 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx @@ -29,11 +29,9 @@ import { WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID, MAX_WORKSPACE_PICKER_NUM, - WORKSPACE_DETAIL_APP_ID, } from '../../../common/constants'; -import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; -import { ALL_USE_CASE_ID, CoreStart, WorkspaceObject } from '../../../../../core/public'; -import { getFirstUseCaseOfFeatureConfigs } from '../../utils'; +import { CoreStart, WorkspaceObject } from '../../../../../core/public'; +import { getFirstUseCaseOfFeatureConfigs, getUseCaseUrl } from '../../utils'; import { recentWorkspaceManager } from '../../recent_workspace_manager'; import { WorkspaceUseCase } from '../../types'; import { navigateToWorkspaceDetail } from '../utils/workspace'; @@ -134,15 +132,7 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { const getWorkspaceListGroup = (filterWorkspaceList: WorkspaceObject[], itemType: string) => { const listItems = filterWorkspaceList.map((workspace: WorkspaceObject) => { const useCase = getUseCase(workspace); - const appId = - (useCase?.id !== ALL_USE_CASE_ID && useCase?.features?.[0]) || WORKSPACE_DETAIL_APP_ID; - const useCaseURL = formatUrlWithWorkspaceId( - coreStart.application.getUrlForApp(appId, { - absolute: false, - }), - workspace.id, - coreStart.http.basePath - ); + const useCaseURL = getUseCaseUrl(useCase, workspace, coreStart.application, coreStart.http); return ( { savedObjects: [ { id: 'id1', - get: () => { - return 'mock_value'; + get: (param: string) => { + switch (param) { + case 'title': + return 'title1'; + case 'description': + return 'description1'; + case 'dataSourceEngineType': + return 'dataSourceEngineType1'; + case 'auth': + return 'mock_value'; + } }, }, ], @@ -389,8 +398,10 @@ describe('workspace utils: getDataSourcesList', () => { expect(await getDataSourcesList(mockedSavedObjectClient, [])).toStrictEqual([ { id: 'id1', - title: 'mock_value', + title: 'title1', auth: 'mock_value', + description: 'description1', + dataSourceEngineType: 'dataSourceEngineType1', }, ]); }); diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index dc01e64182eb..8d6049feac28 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -11,6 +11,8 @@ import { ALL_USE_CASE_ID, CoreStart, ChromeBreadcrumb, + ApplicationStart, + HttpSetup, } from '../../../core/public'; import { App, @@ -23,6 +25,7 @@ import { } from '../../../core/public'; import { DEFAULT_SELECTED_FEATURES_IDS, WORKSPACE_DETAIL_APP_ID } from '../common/constants'; import { WorkspaceUseCase } from './types'; +import { formatUrlWithWorkspaceId } from '../../../core/public/utils'; import { SigV4ServiceName } from '../../../plugins/data_source/common/data_sources'; export const USE_CASE_PREFIX = 'use-case-'; @@ -203,7 +206,7 @@ export const getDataSourcesList = (client: SavedObjectsStart['client'], workspac return client .find({ type: 'data-source', - fields: ['id', 'title', 'auth'], + fields: ['id', 'title', 'auth', 'description', 'dataSourceEngineType'], perPage: 10000, workspaces, }) @@ -214,10 +217,14 @@ export const getDataSourcesList = (client: SavedObjectsStart['client'], workspac const id = source.id; const title = source.get('title'); const auth = source.get('auth'); + const description = source.get('description'); + const dataSourceEngineType = source.get('dataSourceEngineType'); return { id, title, auth, + description, + dataSourceEngineType, }; }); } else { @@ -362,3 +369,21 @@ export function prependWorkspaceToBreadcrumbs( }); } } + +export const getUseCaseUrl = ( + useCase: WorkspaceUseCase | undefined, + workspace: WorkspaceObject, + application: ApplicationStart, + http: HttpSetup +): string => { + const appId = + (useCase?.id !== ALL_USE_CASE_ID && useCase?.features?.[0]) || WORKSPACE_DETAIL_APP_ID; + const useCaseURL = formatUrlWithWorkspaceId( + application.getUrlForApp(appId, { + absolute: false, + }), + workspace.id, + http.basePath + ); + return useCaseURL; +}; diff --git a/src/plugins/workspace/public/workspace_client.ts b/src/plugins/workspace/public/workspace_client.ts index d9931f95c135..6482478c9240 100644 --- a/src/plugins/workspace/public/workspace_client.ts +++ b/src/plugins/workspace/public/workspace_client.ts @@ -232,6 +232,9 @@ export class WorkspaceClient { const result = await this.safeFetch(this.getPath(id), { method: 'DELETE' }); if (result.success) { + // After deleting workspace, need to reset current workspace ID. + this.workspaces.currentWorkspaceId$.next(''); + await this.updateWorkspaceList(); } From 85389c5dfc9a5642c3a3fc199d6b20fa17c0aded Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 11:21:17 +0800 Subject: [PATCH 204/276] fix bug: management section id not match the key defined in capabilities (#6421) (#7634) * fix management section id not match the key defined in capabilities * add descriptions on how the PR solved the problme --------- (cherry picked from commit a65a8aa5b13c5ffbca46b5685b5799efb2dd4af9) Signed-off-by: Yulong Ruan Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- src/plugins/management/common/contants.ts | 14 ++++++++++ .../management_sections_service.test.ts | 28 +++++++++++++++++++ .../public/management_sections_service.ts | 21 ++++++++++++-- .../server/capabilities_provider.ts | 17 ++--------- 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/plugins/management/common/contants.ts b/src/plugins/management/common/contants.ts index 47e418fc620f..037df0ad7c52 100644 --- a/src/plugins/management/common/contants.ts +++ b/src/plugins/management/common/contants.ts @@ -29,3 +29,17 @@ */ export const MANAGEMENT_APP_ID = 'management'; +export const DEFAULT_MANAGEMENT_CAPABILITIES = { + management: { + /* + * Management settings correspond to management section/link ids, and should not be changed + * without also updating those definitions. + */ + opensearchDashboards: { + settings: true, + indexPatterns: true, + objects: true, + dataSources: true, + }, + }, +}; diff --git a/src/plugins/management/public/management_sections_service.test.ts b/src/plugins/management/public/management_sections_service.test.ts index 8f969bce8996..e0358fac99a3 100644 --- a/src/plugins/management/public/management_sections_service.test.ts +++ b/src/plugins/management/public/management_sections_service.test.ts @@ -28,6 +28,7 @@ * under the License. */ +import { DEFAULT_MANAGEMENT_CAPABILITIES } from '../common/contants'; import { ManagementSectionsService, getSectionsServiceStartPrivate, @@ -105,4 +106,31 @@ describe('ManagementService', () => { ] `); }); + + it('should disable apps register in predefined opensearchDashboards section', () => { + // The management capabilities has `opensearchDashboards` as the key + const originalDataSourcesCapability = + DEFAULT_MANAGEMENT_CAPABILITIES.management.opensearchDashboards.dataSources; + + const setup = managementService.setup(); + + // The predefined opensearchDashboards section has id `opensearch-dashboards` which + // doesn't match the capability id `opensearchDashboards` + setup.section.opensearchDashboards.registerApp({ + id: 'dataSources', + title: 'Data source', + mount: jest.fn(), + }); + + // Now set dataSources to capability to false should disable + // the dataSources app registered in opensearchDashboards section + DEFAULT_MANAGEMENT_CAPABILITIES.management.opensearchDashboards.dataSources = false; + + managementService.start({ capabilities: DEFAULT_MANAGEMENT_CAPABILITIES }); + expect( + setup.section.opensearchDashboards.apps.find((app) => app.id === 'dataSources')?.enabled + ).toBe(false); + + DEFAULT_MANAGEMENT_CAPABILITIES.management.opensearchDashboards.dataSources = originalDataSourcesCapability; + }); }); diff --git a/src/plugins/management/public/management_sections_service.ts b/src/plugins/management/public/management_sections_service.ts index 81b8c7ac24af..4a65388d22e9 100644 --- a/src/plugins/management/public/management_sections_service.ts +++ b/src/plugins/management/public/management_sections_service.ts @@ -51,6 +51,22 @@ const [getSectionsServiceStartPrivate, setSectionsServiceStartPrivate] = createG ManagementSectionsStartPrivate >('SectionsServiceStartPrivate'); +/** + * The management capabilities has `opensearchDashboards` as the key + * While when registering the opensearchDashboards section, the section id is `opensearch-dashboards` + * as defined in {@link ManagementSectionId.OpenSearchDashboards} and section id is used as the capability + * id. Here we have a mapping so that the section id opensearch-dashboards can mapping correctly back to the + * capability id: opensearchDashboards + * + * Why not directly change the capability id to opensearch-dashboards? + * The issue was introduced in https://github.com/opensearch-project/OpenSearch-Dashboards/pull/260 + * Since then, the capability id `opensearchDashboards` has been used by plugins, having a mapping here + * is for backward compatibility + */ +const MANAGEMENT_ID_TO_CAPABILITIES: Record = { + 'opensearch-dashboards': 'opensearchDashboards', +}; + export { getSectionsServiceStartPrivate }; export class ManagementSectionsService { @@ -94,8 +110,9 @@ export class ManagementSectionsService { start({ capabilities }: SectionsServiceStartDeps) { this.getAllSections().forEach((section) => { - if (capabilities.management.hasOwnProperty(section.id)) { - const sectionCapabilities = capabilities.management[section.id]; + const capabilityId = MANAGEMENT_ID_TO_CAPABILITIES[section.id] || section.id; + if (capabilities.management.hasOwnProperty(capabilityId)) { + const sectionCapabilities = capabilities.management[capabilityId]; section.apps.forEach((app) => { if (sectionCapabilities.hasOwnProperty(app.id) && sectionCapabilities[app.id] !== true) { app.disable(); diff --git a/src/plugins/management/server/capabilities_provider.ts b/src/plugins/management/server/capabilities_provider.ts index 2786378c9828..9d67c752f52d 100644 --- a/src/plugins/management/server/capabilities_provider.ts +++ b/src/plugins/management/server/capabilities_provider.ts @@ -28,17 +28,6 @@ * under the License. */ -export const capabilitiesProvider = () => ({ - management: { - /* - * Management settings correspond to management section/link ids, and should not be changed - * without also updating those definitions. - */ - opensearchDashboards: { - settings: true, - indexPatterns: true, - objects: true, - dataSources: true, - }, - }, -}); +import { DEFAULT_MANAGEMENT_CAPABILITIES } from '../common/contants'; + +export const capabilitiesProvider = () => DEFAULT_MANAGEMENT_CAPABILITIES; From 23ff2617ebbe502b03cb7e87f1c10a698e660f5a Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Sun, 18 Aug 2024 21:02:21 -0700 Subject: [PATCH 205/276] Update Recent popover to always render breadcrumbs with full length (#7735) (#7742) (cherry picked from commit 389ad1b7ed8a32ea67b12918c56cb3c442fb0e63) Signed-off-by: Zhongnan Su Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../ui/header/__snapshots__/header.test.tsx.snap | 3 ++- src/core/public/chrome/ui/header/header.tsx | 6 +++--- .../public/chrome/ui/header/header_breadcrumbs.tsx | 4 +++- src/core/public/chrome/ui/header/recent_items.tsx | 14 +++----------- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index 82aa02fe79a0..32808a758a65 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -8591,7 +8591,6 @@ exports[`Header renders application header without title and breadcrumbs 1`] = ` } } buttonSize="s" - headerVariant="application" navLinks$={ BehaviorSubject { "_isScalar": false, @@ -8845,6 +8844,7 @@ exports[`Header renders application header without title and breadcrumbs 1`] = ` "thrownError": null, } } + renderFullLength={true} useUpdatedHeader={true} /> } @@ -17327,6 +17327,7 @@ exports[`Header renders page header with application title 1`] = ` "thrownError": null, } } + renderFullLength={true} useUpdatedHeader={true} /> } diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index 9bffb2f0c406..da1aa287e029 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -208,12 +208,13 @@ export function Header({ /> ); - const renderBreadcrumbs = () => ( + const renderBreadcrumbs = (renderFullLength?: boolean) => ( ); @@ -354,8 +355,7 @@ export function Header({ navigateToUrl={application.navigateToUrl} navLinks$={observables.navLinks$} basePath={basePath} - headerVariant={headerVariant} - renderBreadcrumbs={renderBreadcrumbs()} + renderBreadcrumbs={renderBreadcrumbs(true)} buttonSize={useApplicationHeader ? 's' : 'xs'} /> diff --git a/src/core/public/chrome/ui/header/header_breadcrumbs.tsx b/src/core/public/chrome/ui/header/header_breadcrumbs.tsx index cac19ae160af..5361db221d10 100644 --- a/src/core/public/chrome/ui/header/header_breadcrumbs.tsx +++ b/src/core/public/chrome/ui/header/header_breadcrumbs.tsx @@ -41,6 +41,7 @@ interface Props { breadcrumbs$: Observable; breadcrumbsEnricher$: Observable; useUpdatedHeader?: boolean; + renderFullLength?: boolean; } export function HeaderBreadcrumbs({ @@ -48,6 +49,7 @@ export function HeaderBreadcrumbs({ breadcrumbs$, breadcrumbsEnricher$, useUpdatedHeader, + renderFullLength, }: Props) { const appTitle = useObservable(appTitle$, 'OpenSearch Dashboards'); const breadcrumbs = useObservable(breadcrumbs$, []); @@ -87,7 +89,7 @@ export function HeaderBreadcrumbs({ return ( Promise; basePath: HttpStart['basePath']; navLinks$: Rx.Observable; - headerVariant?: HeaderVariant; renderBreadcrumbs: React.JSX.Element; buttonSize?: EuiHeaderSectionItemButtonProps['size']; } @@ -41,7 +40,6 @@ export const RecentItems = ({ navigateToUrl, navLinks$, basePath, - headerVariant, renderBreadcrumbs, buttonSize = 's', }: Props) => { @@ -69,8 +67,6 @@ export const RecentItems = ({ setIsPopoverOpen(false); }; - const appendBreadcrumbs = Boolean(headerVariant === HeaderVariant.APPLICATION); - return ( - {appendBreadcrumbs ? ( - <> - {renderBreadcrumbs} - - - ) : null} + {renderBreadcrumbs} +

Recents

From 1e5addb9f1a1e64d68c8e7e9a9c66dc4dc3f4392 Mon Sep 17 00:00:00 2001 From: Viraj Sanghvi Date: Mon, 19 Aug 2024 09:06:01 -0700 Subject: [PATCH 206/276] refactor: simplify theme configuration and defaulting (#7625) (#7746) --------- Signed-off-by: Viraj Sanghvi Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> (cherry picked from commit bcdbbef7b5ef42b10bdf9aa65ef8b96c126dba82) --- changelogs/fragments/7625.yml | 5 + docs/theme.md | 162 ++++++++++++++++++ .../osd-optimizer/src/common/theme_tags.ts | 9 +- packages/osd-ui-shared-deps/index.d.ts | 10 +- packages/osd-ui-shared-deps/index.js | 5 + packages/osd-ui-shared-deps/theme.ts | 9 +- packages/osd-ui-shared-deps/theme_config.d.ts | 41 +++++ packages/osd-ui-shared-deps/theme_config.js | 44 +++++ .../ui_settings_client.test.ts.snap | 13 ++ src/core/public/ui_settings/types.ts | 7 + .../ui_settings/ui_settings_client.test.ts | 18 ++ .../public/ui_settings/ui_settings_client.ts | 37 ++-- .../ui_settings/ui_settings_service.mock.ts | 1 + .../server/rendering/rendering_service.tsx | 7 +- src/core/server/ui_settings/settings/theme.ts | 13 +- src/core/server/ui_settings/types.ts | 4 + .../ui_settings/ui_settings_client.test.ts | 19 ++ .../server/ui_settings/ui_settings_client.ts | 4 + .../server/ui_settings/ui_settings_config.ts | 4 +- .../ui_settings/ui_settings_service.mock.ts | 1 + .../ui/ui_render/bootstrap/startup.js.hbs | 8 +- src/legacy/ui/ui_render/ui_render_mixin.js | 31 ++-- .../public/header_user_theme_menu.tsx | 28 ++- .../dashboard_top_nav.test.tsx.snap | 6 + .../dashboard_empty_screen.test.tsx.snap | 3 + .../language_selector.test.tsx.snap | 2 + 26 files changed, 426 insertions(+), 65 deletions(-) create mode 100644 changelogs/fragments/7625.yml create mode 100644 docs/theme.md create mode 100644 packages/osd-ui-shared-deps/theme_config.d.ts create mode 100644 packages/osd-ui-shared-deps/theme_config.js diff --git a/changelogs/fragments/7625.yml b/changelogs/fragments/7625.yml new file mode 100644 index 000000000000..e4ce4fbe7e57 --- /dev/null +++ b/changelogs/fragments/7625.yml @@ -0,0 +1,5 @@ +refactor: +- Simplify theme configuration and defaulting ([#7625](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7625)) + +deprecate: +- Deprecating `CssDistFilename` exports in favor of `themeCssDistFilenames` in `@osd/ui-shared-deps` ([#7625](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7625)) \ No newline at end of file diff --git a/docs/theme.md b/docs/theme.md new file mode 100644 index 000000000000..96873d1cbdff --- /dev/null +++ b/docs/theme.md @@ -0,0 +1,162 @@ +# Theme System + +## Basic concepts + +### Theme definitions in OUI + +Themes are defined in OUI via https://github.com/opensearch-project/oui/blob/main/src/themes/themes.ts. When Building OUI, there are several theming artifacts generated (beyond the react components) for each mode (light/dark) of each theme: + +1. Theme compiled stylesheets (e.g. `@elastic/eui/dist/eui_theme_dark.css`). Consumed as entry files in [/packages/osd-ui-shared-deps/webpack.config.js](/packages/osd-ui-shared-deps/webpack.config.js) and republished by `osd-ui-shared-deps` (e.g. [UiSharedDeps.themeCssDistFilenames](/packages/osd-ui-shared-deps/index.js)). +2. Theme compiled and minified stylesheets (e.g. `@elastic/eui/dist/eui_theme_dark.min.css`). These appear unused by OpenSearch Dashboards +3. Theme computed SASS variables as JSON (e.g. `@elastic/eui/dist/eui_theme_dark.json`). Consumed by [/packages/osd-ui-shared-deps/theme.ts](/packages/osd-ui-shared-deps/theme.ts) and made available to other components via the mode and theme aware `euiThemeVars`. In general, these should not be consumed by any other component directly. +4. Theme type definition file for SASS variables as JSON (e.g. `@elastic/eui/dist/eui_theme_dark.json.d.ts`) + +Note that all of these artifacts should ideally only be imported or used directly in one place (by `osd-ui-shared-deps`). + +In addition to these artifacts, OpenSearch Dashboards also makes heavy use of the theme SASS variables and mixins as defined in the source files (e.g. `@elastic/eui/src/theme_dark.scss`). + +### Theme definitions in OpenSearch Dashboards + +1. Theme tags are defined in [/packages/osd-optimizer/src/common/theme_tags.ts](/packages/osd-optimizer/src/common/theme_tags.ts) corresponding to each mode (light/dark) of each OUI theme. +2. These tags must correspond to entrypoint SCSS files in [/src/core/public/core_app/styles/](/src/core/public/core_app/styles/_globals_v8dark.scss), because they are imported by all SCSS files as part of the `sass-loader` in [/packages/osd-optimizer/src/worker/webpack.config.ts](/packages/osd-optimizer/src/worker/webpack.config.ts) and [/packages/osd-optimizer/src/worker/theme_loader.ts](/packages/osd-optimizer/src/worker/theme_loader.ts). Note that the optimizer webpack will compile a separate stylesheet for each unique mode and theme combination. +3. OUI SCSS source files are also imported by `osd-ui-framework`, which generates the legacy KUI stylesheets (e.g. [/packages/osd-ui-framework/src/kui_next_dark.scss](/packages/osd-ui-framework/src/kui_next_dark.scss)). KUI is a UI library that predates EUI/OUI, and should be deprecated and fully removed via [#1060](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/1060). Because it's a legacy package it has its own build process that doesn't use webpack; it just [compiles the SCSS files with grunt](/packages/osd-ui-framework/Gruntfile.js). But similarly to 2., a separate stylesheet is generated for each mode and theme combination. + +### Thmemed assets in OpenSearch Dasboards + +In general, most themed assests can be found in [/src/core/server/core_app/assets](src/core/server/core_app/assets/fonts/readme.md) (it also includes non-themed assets such as `favicons`, which could easily be themed if desired in the future). + +Most of the graphics/images are only dark/light mode-specific, not theme-specific: + +1. `default_branding` marks +2. `logos` + +This directory also includes legacy CSS files ([/src/core/server/core_app/assets/legacy_dark_theme.css](/src/core/server/core_app/assets/legacy_dark_theme.css) and [/src/core/server/core_app/assets/legacy_light_theme.css](/src/core/server/core_app/assets/legacy_light_theme.css)), which predate even KUI, and are still used by some plugins (notably `discover`). See [#4385](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4385) for an experiment in removing these. Unlike KUI, they don't rely on OUI themes at all. + +Finally, font assets are a bit of a special case. Theme-specific fonts are defined by OUI, but it doesn't include the font definitions directly. Instead, the font assets are in [/src/core/server/core_app/assets/fonts](/src/core/server/core_app/assets/fonts/readme.md). The corresponding `@font-face` style definitions are generated at runtime via [/src/core/server/rendering/views/fonts.tsx](/src/core/server/rendering/views/fonts.tsx). + +## Theme settings + +## Theme loading + +```mermaid +sequenceDiagram + autonumber + critical Setup + core/server->>core/server/rendering: setup rendering service + core/server/rendering->>core/server: provide render() method + core/server->>core/server: setup legacy service + core/server->>legacy: create legacy server + legacy->>legacy: start ui mixin to
handle special routes + core/server->>core/server/core_app: setup core app + core/server/core_app->>core/server/core_app: register default routes + core/server/core_app->>core/server/core_app: register static asset dir routes + end + Browser->>core/server: OSD page request (e.g. /app/home#/ ) + core/server->>core/server/core_app: request to default route
(via `http` service) + core/server/core_app->>core/server: call renderCoreApp() + core/server->>core/server/rendering: call render() + critical Initial page bootstrap + core/server/rendering->>core/server/rendering: get theme settings from config + core/server/rendering->>core/server/rendering: assign branding values \
(including dark mode) + core/server/rendering->>Browser: return static loading page template + Note over core/server/rendering,Browser: includes inlined font-face styles and static loading page styles + critical (render blocking) + Browser->>Browser: define injection points + Browser->>Browser: load static loading page styles + Browser->>Browser: load font-face styles + Browser->>legacy: load startup.js special route + legacy->>legacy: build startup.js from template + Note over legacy: inject theme settings and font sources + legacy->>Browser: startup.js + critical startup.js + Browser->>Browser: get theme preferences from local storage + Browser->>Browser: set global theme tag + Browser->>Browser: inject theme-specific loading page styles + Browser->>Browser: inject theme-specific font css vars + end + end + Browser->>Browser: render loading/error page
(with loaders hidden) + Browser->>legacy: load bootstrap.js special route + legacy->>legacy: build bootstrap.js from template + legacy->>Browser: bootstrap.js + critical bootstrap.js + Browser->>Browser: toggle visibility of errors/loaders + Browser->>Browser: get theme preferences from local storage + Browser->>core/server/core_app: load js bundles + core/server/core_app->>Browser: (React application) + Browser->>core/server/core_app: load theme-specific stylesheets
(base, OUI, KUI, legacy) + core/server/core_app->>Browser: themed css + end + end +``` + +### Loading + +`src/legacy/ui/ui_render/ui_render_mixin.js` via `src/legacy/ui/ui_render/bootstrap/template.js.hbs` and `src/legacy/ui/ui_render/bootstrap/app_bootstrap.js`. Aliased in `src/legacy/ui/ui_mixin.js`, called by `src/legacy/server/osd_server.js`. Called by `src/core/server/legacy/legacy_service.ts` via `src/core/server/server.ts` + +### Injected style tags + +1. `src/core/server/rendering/views/styles.tsx` - depends on dark/light mode and injects style tag in head +2. `src/core/server/rendering/views/fonts.tsx` - depends on theme version and injects font style tag in head +3. Monaco editor styles +4. Ace styles +5. Ace TM overrides +6. Ace error styles +6. Component styles + +### Styleshsheets loaded + +Each of the following are loaded in the browser by the [bootstrap script](/src/legacy/ui/ui_render/bootstrap/template.js.hbs) in this order. Currently, these are never unloaded. + +1. Monaco editor styles (e.g. [/packages/osd-ui-shared-deps/target/osd-ui-shared-deps.css](/packages/osd-ui-shared-deps/target/osd-ui-shared-deps.css)), packaged by [/packages/osd-ui-shared-deps/webpack.config.js](/packages/osd-ui-shared-deps/webpack.config.js). In theory, this file could include styles from other shared dependencies, but currently `osd-monaco` is the only package that exports styles. Note that these are the default, un-themed styles; theming of monaco editors is handled by [/src/plugins/opensearch_dashboards_react/public/code_editor/editor_theme.ts](/src/plugins/opensearch_dashboards_react/public/code_editor/editor_theme.ts). +2. Theme and mode-specific OUI styles (e.g. [](), compiled by `packages/osd-ui-shared-deps/webpack.config.js`). +3. Theme and mode-specific KUI styles (e.g. `packages/osd-ui-framework/src/kui_next_dark.scss`, compiled by `packages/osd-ui-framework/Gruntfile.js`). Separate stylesheets for each theme version/dark mode combo (colors). +4. Mode-specific legacy styles (e.g. [/src/core/server/core_app/assets/legacy_dark_theme.css](/src/core/server/core_app/assets/legacy_dark_theme.css)) + +Component styles are not loaded as stylesheets. + +## Current theme usage + +### JSON/JS Vars + +1. Defined by `packages/osd-ui-shared-deps/theme.ts` + 1. Used by `src/plugins/charts/public/static/color_maps/color_maps.ts` to set vis colors + 2. Used by `src/plugins/discover/public/application/components/chart/histogram/histogram.tsx` to define Discover histogram Elastic Chart styling + 3. Used by `src/plugins/maps_legacy/public/map/opensearch_dashboards_map.js` and `src/plugins/region_map/public/choropleth_layer.js` for minor map UI styling (line color, empty shade) + 4. Used by `src/plugins/vis_type_vega/public/data_model/vega_parser.ts` for Vega/Vega-Lite theming +2. Used by `src/plugins/vis_type_vislib/public/vislib/components/tooltip/tooltip.js` for tooltip spacing +3. Used by `src/plugins/expressions/public/react_expression_renderer.tsx` to define padding options. +4. Used by `src/core/server/rendering/views/theme.ts` to inject values into `src/core/server/rendering/views/styles.tsx` +5. Used (incorrectly) to style a badge color in `src/plugins/index_pattern_management/public/components/create_button/create_button.tsx` +6. Used by `src/plugins/opensearch_dashboards_react/public/code_editor/editor_theme.ts` to create Monaco theme styles + +## Theme Management + +### Change default theme + +Update `DEFAULT_THEME_VERSION` in `src/core/server/ui_settings/ui_settings_config.ts` to point to the desired theme version. + +### Adding a new theme + +1. Add a [a new theme to OUI](https://github.com/opensearch-project/oui/blob/main/wiki/theming.md) and publish new OUI version +2. Update OSD to consume new OUI version +3. Make the following changes in OSD: + 1. Load your theme by creating sass files in `src/core/public/core_app/styles` + 2. Update [webpack config](packages/osd-ui-shared-deps/webpack.config.js) to create css files for your theme + 2. Add kui css files: + 1. Create kui sass files for your theme in `packages/osd-ui-framework/src/` + 2. Update `packages/osd-ui-framework/Gruntfile.js` to build these files + 3. Generate the files by running `npx grunt compileCss` from this package root + 3. Add fonts to OSD: + 1. Make sure your theme fonts are in [/src/core/server/core_app/assets/fonts](/src/core/server/core_app/assets/fonts/readme.md) + 2. Update `src/core/server/rendering/views/fonts.tsx` to reference those files + 3. Update src/core/server/core_app/assets/fonts/readme.md to reference the fonts + 4. Update `packages/osd-ui-shared-deps/theme_config.js`: + 1. Add version and label for version to `THEME_VERSION_LABEL_MAP` + 2. Update `kuiCssDistFilenames` map for new theme + 3. Update `ThemeTag` type in corresponding definition file (`theme_config.d.ts`) + 5. Load variables for new theme in `packages/osd-ui-shared-deps/theme.ts'` + 6. Update `src/legacy/ui/ui_render/ui_render_mixin.js': + 1. Load variables for your theme in `THEME_SOURCES` + 2. Define the text font for your theme in `fontText` + 3. Define the code font for your theme in `fontCode` diff --git a/packages/osd-optimizer/src/common/theme_tags.ts b/packages/osd-optimizer/src/common/theme_tags.ts index 8170c6bcab69..3078a9c6dc06 100644 --- a/packages/osd-optimizer/src/common/theme_tags.ts +++ b/packages/osd-optimizer/src/common/theme_tags.ts @@ -28,6 +28,8 @@ * under the License. */ +import { themeTags as THEME_TAGS } from '@osd/ui-shared-deps'; +import type { ThemeTag, ThemeTags } from '@osd/ui-shared-deps'; import { ascending } from './array_helpers'; const tags = (...themeTags: string[]) => @@ -37,10 +39,9 @@ const validTag = (tag: any): tag is ThemeTag => ALL_THEMES.includes(tag); const isArrayOfStrings = (input: unknown): input is string[] => Array.isArray(input) && input.every((v) => typeof v === 'string'); -export type ThemeTags = readonly ThemeTag[]; -export type ThemeTag = 'v7light' | 'v7dark' | 'v8light' | 'v8dark'; -export const DEFAULT_THEMES = tags('v7light', 'v7dark', 'v8light', 'v8dark'); -export const ALL_THEMES = tags('v7light', 'v7dark', 'v8light', 'v8dark'); +export type { ThemeTag, ThemeTags }; +export const DEFAULT_THEMES = tags(...THEME_TAGS); +export const ALL_THEMES = tags(...THEME_TAGS); export function parseThemeTags(input?: any): ThemeTags { if (!input) { diff --git a/packages/osd-ui-shared-deps/index.d.ts b/packages/osd-ui-shared-deps/index.d.ts index 49192a18d291..4e03db427bd4 100644 --- a/packages/osd-ui-shared-deps/index.d.ts +++ b/packages/osd-ui-shared-deps/index.d.ts @@ -43,6 +43,11 @@ export const jsFilename: string; */ export const jsDepFilenames: string[]; +/** + * Re-export all types from theme_config + */ +export * from './theme_config'; + /** * Filename of the unthemed css file in the distributable directory */ @@ -50,24 +55,27 @@ export const baseCssDistFilename: string; /** * Filename of the dark-theme css file in the distributable directory + * @deprecated */ export const darkCssDistFilename: string; /** * Filename of the dark-theme css file in the distributable directory + * @deprecated */ export const darkV8CssDistFilename: string; /** * Filename of the light-theme css file in the distributable directory + * @deprecated */ export const lightCssDistFilename: string; /** * Filename of the light-theme css file in the distributable directory + * @deprecated */ export const lightV8CssDistFilename: string; - /** * Externals mapping inteded to be used in a webpack config */ diff --git a/packages/osd-ui-shared-deps/index.js b/packages/osd-ui-shared-deps/index.js index 36218a28d4eb..fe3de2b1f003 100644 --- a/packages/osd-ui-shared-deps/index.js +++ b/packages/osd-ui-shared-deps/index.js @@ -30,13 +30,18 @@ const Path = require('path'); +Object.assign(exports, require('./theme_config')); exports.distDir = Path.resolve(__dirname, 'target'); exports.jsDepFilenames = ['osd-ui-shared-deps.@elastic.js']; exports.jsFilename = 'osd-ui-shared-deps.js'; exports.baseCssDistFilename = 'osd-ui-shared-deps.css'; +/** @deprecated */ exports.lightCssDistFilename = 'osd-ui-shared-deps.v7.light.css'; +/** @deprecated */ exports.lightV8CssDistFilename = 'osd-ui-shared-deps.v8.light.css'; +/** @deprecated */ exports.darkCssDistFilename = 'osd-ui-shared-deps.v7.dark.css'; +/** @deprecated */ exports.darkV8CssDistFilename = 'osd-ui-shared-deps.v8.dark.css'; exports.externals = { // stateful deps diff --git a/packages/osd-ui-shared-deps/theme.ts b/packages/osd-ui-shared-deps/theme.ts index c803a5e37ef7..082f468175e2 100644 --- a/packages/osd-ui-shared-deps/theme.ts +++ b/packages/osd-ui-shared-deps/theme.ts @@ -37,13 +37,14 @@ export type Theme = typeof LightTheme; // in the OpenSearch Dashboards app we can rely on this global being defined, but in // some cases (like jest) the global is undefined -export const tag: string = globals.__osdThemeTag__ || 'v8light'; -export const version = tag.startsWith('v7') ? 7 : 8; -export const darkMode = tag.endsWith('dark'); +export const tag: string = globals.__osdThemeTag__; +const themeVersion = tag?.replace(/(light|dark)$/, '') || 'v8'; +export const version = parseInt(themeVersion.replace(/[^\d]+/g, ''), 10) || 8; +export const darkMode = tag?.endsWith?.('dark'); export let euiLightVars: Theme; export let euiDarkVars: Theme; -if (version === 7) { +if (themeVersion === 'v7') { euiLightVars = require('@elastic/eui/dist/eui_theme_light.json'); euiDarkVars = require('@elastic/eui/dist/eui_theme_dark.json'); } else { diff --git a/packages/osd-ui-shared-deps/theme_config.d.ts b/packages/osd-ui-shared-deps/theme_config.d.ts new file mode 100644 index 000000000000..0ca80280434f --- /dev/null +++ b/packages/osd-ui-shared-deps/theme_config.d.ts @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Types for valid theme tags (themeVersion + themeMode) + * Note: used by @osd/optimizer + */ +export type ThemeTag = 'v7light' | 'v7dark' | 'v8light' | 'v8dark'; +export type ThemeTags = readonly ThemeTag[]; + +/** + * List of valid ThemeTags + * Note: used by @osd/optimizer + */ +export const themeTags: ThemeTags; + +/** + * Map of themeVersion values to labels + * Note: this is used for ui display + */ +export const themeVersionLabelMap: Record; + +/** + * Map of labels and versions to themeVersion values + * Note: this is used to correct incorrectly persisted ui settings + */ +export const themeVersionValueMap: Record; + +/** + * Theme CSS distributable filenames by themeVersion and themeMode + * Note: used by bootstrap template + */ +export const themeCssDistFilenames: Record>; + +/** + * KUI CSS distributable filenames by themeVersion and themeMode + * Note: used by bootstrap template + */ +export const kuiCssDistFilenames: Record>; diff --git a/packages/osd-ui-shared-deps/theme_config.js b/packages/osd-ui-shared-deps/theme_config.js new file mode 100644 index 000000000000..f128925bbbcb --- /dev/null +++ b/packages/osd-ui-shared-deps/theme_config.js @@ -0,0 +1,44 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * The purpose of this file is to centalize theme configuration so it can be used across server, + * client, and dev tooling. DO NOT add dependencies that wouldn't operate in all of these contexts. + * + * Default theme is specified in the uiSettings schema. + */ + +const THEME_MODES = ['light', 'dark']; +const THEME_VERSION_LABEL_MAP = { + v7: 'v7', + v8: 'Next (preview)', +}; +const THEME_VERSION_VALUE_MAP = { + // allow version lookup by label ... + ...Object.fromEntries(Object.entries(THEME_VERSION_LABEL_MAP).map((a) => a.reverse())), + // ... or by the version itself + ...Object.fromEntries(Object.keys(THEME_VERSION_LABEL_MAP).map((v) => [v, v])), +}; +const THEME_VERSIONS = Object.keys(THEME_VERSION_LABEL_MAP); +const THEME_TAGS = THEME_VERSIONS.flatMap((v) => THEME_MODES.map((m) => `${v}${m}`)); + +exports.themeVersionLabelMap = THEME_VERSION_LABEL_MAP; + +exports.themeVersionValueMap = THEME_VERSION_VALUE_MAP; + +exports.themeTags = THEME_TAGS; + +exports.themeCssDistFilenames = THEME_VERSIONS.reduce((map, v) => { + map[v] = THEME_MODES.reduce((acc, m) => { + acc[m] = `osd-ui-shared-deps.${v}.${m}.css`; + return acc; + }, {}); + return map; +}, {}); + +exports.kuiCssDistFilenames = { + v7: { dark: 'kui_dark.css', light: 'kui_light.css' }, + v8: { dark: 'kui_next_dark.css', light: 'kui_next_light.css' }, +}; diff --git a/src/core/public/ui_settings/__snapshots__/ui_settings_client.test.ts.snap b/src/core/public/ui_settings/__snapshots__/ui_settings_client.test.ts.snap index 68948ef0d4af..5d0b95e2938b 100644 --- a/src/core/public/ui_settings/__snapshots__/ui_settings_client.test.ts.snap +++ b/src/core/public/ui_settings/__snapshots__/ui_settings_client.test.ts.snap @@ -20,6 +20,19 @@ You can use \`IUiSettingsClient.get(\\"throwableProperty\\", defaultValue)\`, wh \`defaultValue\` when the key is unrecognized." `; +exports[`#getDefault converts json default values 1`] = ` +Object { + "a": 1, +} +`; + +exports[`#getDefault fetches correct uiSettings defaults 1`] = `"Browser"`; + +exports[`#getDefault throws on unknown properties that don't have a value yet. 1`] = ` +"Unexpected \`IUiSettingsClient.getDefaultValue(\\"unknownProperty\\")\` call on unrecognized configuration setting \\"unknownProperty\\". +Please check that the setting for \\"unknownProperty\\" exists." +`; + exports[`#getUpdate$ sends { key, newValue, oldValue } notifications when client changes 1`] = ` Array [ Array [ diff --git a/src/core/public/ui_settings/types.ts b/src/core/public/ui_settings/types.ts index 7eca4cc68d81..86f78443eee6 100644 --- a/src/core/public/ui_settings/types.ts +++ b/src/core/public/ui_settings/types.ts @@ -66,6 +66,13 @@ export interface IUiSettingsClient { */ getAll: () => Readonly>; + /** + * Gets the default value for a specific uiSetting. If the parameter is not defined and the key is + * not registered by any plugin then an error is thrown, otherwise reads the default value defined by + * a plugin. + */ + getDefault: (key: string) => T; + /** * Sets the value for a uiSetting. If the setting is not registered by any plugin * it will be stored as a custom setting. The new value will be synchronously available via diff --git a/src/core/public/ui_settings/ui_settings_client.test.ts b/src/core/public/ui_settings/ui_settings_client.test.ts index 9060b0d6db4e..9cf4985f440c 100644 --- a/src/core/public/ui_settings/ui_settings_client.test.ts +++ b/src/core/public/ui_settings/ui_settings_client.test.ts @@ -64,6 +64,24 @@ afterEach(() => { done$.complete(); }); +describe('#getDefault', () => { + it('fetches correct uiSettings defaults', () => { + const { client } = setup(); + expect(client.getDefault('dateFormat')).toMatchSnapshot(); + expect(client.getDefault('aLongNumeral')).toBe(BigInt(Number.MAX_SAFE_INTEGER) + 11n); + }); + + it('converts json default values', () => { + const { client } = setup({ defaults: { test: { value: '{"a": 1}', type: 'json' } } }); + expect(client.getDefault('test')).toMatchSnapshot(); + }); + + it("throws on unknown properties that don't have a value yet.", () => { + const { client } = setup(); + expect(() => client.getDefault('unknownProperty')).toThrowErrorMatchingSnapshot(); + }); +}); + describe('#get', () => { it('gives access to uiSettings values', () => { const { client } = setup(); diff --git a/src/core/public/ui_settings/ui_settings_client.ts b/src/core/public/ui_settings/ui_settings_client.ts index 8a5701de6b39..ac548278bf47 100644 --- a/src/core/public/ui_settings/ui_settings_client.ts +++ b/src/core/public/ui_settings/ui_settings_client.ts @@ -32,7 +32,7 @@ import { cloneDeep, defaultsDeep } from 'lodash'; import { Observable, Subject, concat, defer, of } from 'rxjs'; import { filter, map } from 'rxjs/operators'; -import { UserProvidedValues, PublicUiSettingsParams } from 'src/core/server/types'; +import { UserProvidedValues, PublicUiSettingsParams, UiSettingsType } from 'src/core/server/types'; import { IUiSettingsClient, UiSettingsState } from './types'; import { UiSettingsApi } from './ui_settings_api'; @@ -71,6 +71,18 @@ export class UiSettingsClient implements IUiSettingsClient { return cloneDeep(this.cache); } + getDefault(key: string): T { + const declared = this.isDeclared(key); + + if (!declared) { + throw new Error( + `Unexpected \`IUiSettingsClient.getDefaultValue("${key}")\` call on unrecognized configuration setting "${key}". +Please check that the setting for "${key}" exists.` + ); + } + return this.resolveValue(this.cache[key].value, this.cache[key].type); + } + get(key: string, defaultOverride?: T) { const declared = this.isDeclared(key); @@ -92,16 +104,7 @@ You can use \`IUiSettingsClient.get("${key}", defaultValue)\`, which will just r const userValue = this.cache[key].userValue; const defaultValue = defaultOverride !== undefined ? defaultOverride : this.cache[key].value; const value = userValue == null ? defaultValue : userValue; - - if (type === 'json') { - return JSON.parse(value); - } - - return type === 'number' && typeof value !== 'bigint' - ? isFinite(value) && (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) - ? BigInt(value) - : parseFloat(value) - : value; + return this.resolveValue(value, type); } get$(key: string, defaultOverride?: T) { @@ -173,6 +176,18 @@ You can use \`IUiSettingsClient.get("${key}", defaultValue)\`, which will just r return this.updateErrors$.asObservable(); } + private resolveValue(value: any, type: UiSettingsType | undefined) { + if (type === 'json') { + return JSON.parse(value); + } + + return type === 'number' && typeof value !== 'bigint' + ? isFinite(value) && (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) + ? BigInt(value) + : parseFloat(value) + : value; + } + private assertUpdateAllowed(key: string) { if (this.isOverridden(key)) { throw new Error( diff --git a/src/core/public/ui_settings/ui_settings_service.mock.ts b/src/core/public/ui_settings/ui_settings_service.mock.ts index de9477ed0e08..231627fa53bd 100644 --- a/src/core/public/ui_settings/ui_settings_service.mock.ts +++ b/src/core/public/ui_settings/ui_settings_service.mock.ts @@ -36,6 +36,7 @@ import { IUiSettingsClient } from './types'; const createSetupContractMock = () => { const setupContract: jest.Mocked = { getAll: jest.fn(), + getDefault: jest.fn(), get: jest.fn(), get$: jest.fn(), set: jest.fn(), diff --git a/src/core/server/rendering/rendering_service.tsx b/src/core/server/rendering/rendering_service.tsx index acaee7f42bc5..a94056372667 100644 --- a/src/core/server/rendering/rendering_service.tsx +++ b/src/core/server/rendering/rendering_service.tsx @@ -33,6 +33,7 @@ import { renderToStaticMarkup } from 'react-dom/server'; import { first, take } from 'rxjs/operators'; import { i18n } from '@osd/i18n'; import { Agent as HttpsAgent } from 'https'; +import { themeVersionValueMap } from '@osd/ui-shared-deps'; import Axios from 'axios'; // @ts-expect-error untyped internal module used to prevent axios from using xhr adapter in tests @@ -102,10 +103,14 @@ export class RenderingService { false; // At the very least, the schema should define a default theme; the '' will be unreachable - const themeVersion = + const configuredThemeVersion = (settings.user?.['theme:version']?.userValue ?? uiSettings.getOverrideOrDefault('theme:version')) || ''; + // Validate themeVersion is in valid format + const themeVersion = + themeVersionValueMap[configuredThemeVersion] || + (uiSettings.getDefault('theme:version') as string); const brandingAssignment = await this.assignBrandingConfig( darkMode, diff --git a/src/core/server/ui_settings/settings/theme.ts b/src/core/server/ui_settings/settings/theme.ts index 94dec047ff35..e157da9c514e 100644 --- a/src/core/server/ui_settings/settings/theme.ts +++ b/src/core/server/ui_settings/settings/theme.ts @@ -30,7 +30,10 @@ import { schema } from '@osd/config-schema'; import { i18n } from '@osd/i18n'; +import { themeVersionLabelMap } from '@osd/ui-shared-deps'; +import type { Type } from '@osd/config-schema'; import { UiSettingsParams } from '../../../types'; +import { DEFAULT_THEME_VERSION } from '../ui_settings_config'; export const getThemeSettings = (): Record => { return { @@ -50,9 +53,9 @@ export const getThemeSettings = (): Record => { name: i18n.translate('core.ui_settings.params.themeVersionTitle', { defaultMessage: 'Theme version', }), - value: 'Next (preview)', + value: themeVersionLabelMap[DEFAULT_THEME_VERSION], type: 'select', - options: ['v7', 'Next (preview)'], + options: Object.values(themeVersionLabelMap), description: i18n.translate('core.ui_settings.params.themeVersionText', { defaultMessage: `

Switch between the themes used for the current and next versions of OpenSearch Dashboards. A page refresh is required for the setting to be applied.

{linkText}

`, values: { @@ -62,7 +65,11 @@ export const getThemeSettings = (): Record => { }), requiresPageReload: true, category: ['appearance'], - schema: schema.oneOf([schema.literal('v7'), schema.literal('Next (preview)')]), + schema: schema.oneOf( + Object.keys(themeVersionLabelMap).map((v) => schema.literal(themeVersionLabelMap[v])) as [ + Type + ] + ), }, }; }; diff --git a/src/core/server/ui_settings/types.ts b/src/core/server/ui_settings/types.ts index 60510882755a..399349f33f9e 100644 --- a/src/core/server/ui_settings/types.ts +++ b/src/core/server/ui_settings/types.ts @@ -59,6 +59,10 @@ export interface IUiSettingsClient { * Returns the overridden uiSettings value if one exists, or the registered default if one exists {@link UiSettingsParams} */ getOverrideOrDefault: (key: string) => unknown; + /** + * Returns the registered default if one exists {@link UiSettingsParams} + */ + getDefault: (key: string) => unknown; /** * Retrieves uiSettings values set by the user with fallbacks to default values if not specified. */ diff --git a/src/core/server/ui_settings/ui_settings_client.test.ts b/src/core/server/ui_settings/ui_settings_client.test.ts index f78d77e61848..e30ff651e91b 100644 --- a/src/core/server/ui_settings/ui_settings_client.test.ts +++ b/src/core/server/ui_settings/ui_settings_client.test.ts @@ -601,6 +601,25 @@ describe('ui settings', () => { }); }); + describe('#getDefault()', () => { + it(`returns the promised value for a key`, async () => { + const opensearchDocSource = {}; + const defaults = { dateFormat: { value: chance.word() } }; + const { uiSettings } = setup({ opensearchDocSource, defaults }); + const result = uiSettings.getDefault('dateFormat'); + + expect(result).toBe(defaults.dateFormat.value); + }); + + it(`returns undefined for undefined defaults`, async () => { + const opensearchDocSource = { custom: 'value' }; + const { uiSettings } = setup({ opensearchDocSource }); + const result = uiSettings.getDefault('custom'); + + expect(result).toBe(undefined); + }); + }); + describe('#get()', () => { it('pulls user configuration from OpenSearch', async () => { const opensearchDocSource = {}; diff --git a/src/core/server/ui_settings/ui_settings_client.ts b/src/core/server/ui_settings/ui_settings_client.ts index 066efa34cafd..8744cb3b80da 100644 --- a/src/core/server/ui_settings/ui_settings_client.ts +++ b/src/core/server/ui_settings/ui_settings_client.ts @@ -95,6 +95,10 @@ export class UiSettingsClient implements IUiSettingsClient { return this.isOverridden(key) ? this.overrides[key].value : this.defaults[key]?.value; } + getDefault(key: string): unknown { + return this.defaults[key]?.value; + } + async get(key: string): Promise { const all = await this.getAll(); return all[key]; diff --git a/src/core/server/ui_settings/ui_settings_config.ts b/src/core/server/ui_settings/ui_settings_config.ts index 6924640ca1e5..c539e50cf908 100644 --- a/src/core/server/ui_settings/ui_settings_config.ts +++ b/src/core/server/ui_settings/ui_settings_config.ts @@ -37,6 +37,8 @@ const deprecations: ConfigDeprecationProvider = ({ unused, renameFromRoot }) => renameFromRoot('server.defaultRoute', 'uiSettings.overrides.defaultRoute'), ]; +export const DEFAULT_THEME_VERSION = 'v8'; + /* There are 4 levels of uiSettings: * 1) defaults hardcoded in code * 2) defaults provided in the opensearch_dashboards.yml @@ -56,7 +58,7 @@ const configSchema = schema.object({ overrides: schema.object({}, { unknowns: 'allow' }), defaults: schema.object({ 'theme:darkMode': schema.maybe(schema.boolean({ defaultValue: false })), - 'theme:version': schema.maybe(schema.string({ defaultValue: 'v8' })), + 'theme:version': schema.maybe(schema.string({ defaultValue: DEFAULT_THEME_VERSION })), }), }); diff --git a/src/core/server/ui_settings/ui_settings_service.mock.ts b/src/core/server/ui_settings/ui_settings_service.mock.ts index bb6e9ec64bd5..df34cbe1bf16 100644 --- a/src/core/server/ui_settings/ui_settings_service.mock.ts +++ b/src/core/server/ui_settings/ui_settings_service.mock.ts @@ -40,6 +40,7 @@ const createClientMock = () => { const mocked: jest.Mocked = { getRegistered: jest.fn(), getOverrideOrDefault: jest.fn(), + getDefault: jest.fn(), get: jest.fn(), getAll: jest.fn(), getUserProvided: jest.fn(), diff --git a/src/legacy/ui/ui_render/bootstrap/startup.js.hbs b/src/legacy/ui/ui_render/bootstrap/startup.js.hbs index 2a7e6f28a90b..9534a808c09f 100644 --- a/src/legacy/ui/ui_render/bootstrap/startup.js.hbs +++ b/src/legacy/ui/ui_render/bootstrap/startup.js.hbs @@ -30,14 +30,16 @@ if ({{configEnableUserControl}}) { rawThemeVersion = '{{configThemeVersion}}'; } +var themeSources = {{THEME_SOURCES}}; +var themeVersionValueMap = {{THEME_VERSION_VALUE_MAP}}; + // TODO: source of truth for mapping should be elsewhere var darkMode = rawDarkMode ? 'dark' : 'light'; -var themeVersion = rawThemeVersion === 'v7' ? 'v7' : 'v8'; +var resolvedThemeVersion = themeVersionValueMap[rawThemeVersion]; +var themeVersion = themeSources[resolvedThemeVersion] ? resolvedThemeVersion : '{{defaultThemeVersion}}'; window.__osdThemeTag__ = themeVersion + darkMode; -var themeSources = {{THEME_SOURCES}}; - var themeDefinition = themeSources[themeVersion][darkMode]; var stylesheetTarget = document.querySelector('head meta[name="add-styles-here"]'); diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js index 476c465edb52..24837ba4a085 100644 --- a/src/legacy/ui/ui_render/ui_render_mixin.js +++ b/src/legacy/ui/ui_render/ui_render_mixin.js @@ -96,14 +96,19 @@ export function uiRenderMixin(osdServer, server, config) { !authEnabled || request.auth.isAuthenticated ? await uiSettings.get('theme:darkMode') : uiSettings.getOverrideOrDefault('theme:darkMode'); + const themeMode = darkMode ? 'dark' : 'light'; - const themeVersion = + const configuredThemeVersion = !authEnabled || request.auth.isAuthenticated ? await uiSettings.get('theme:version') : uiSettings.getOverrideOrDefault('theme:version'); + // Validate themeVersion is in valid format + const themeVersion = + UiSharedDeps.themeVersionValueMap[configuredThemeVersion] || + uiSettings.getDefault('theme:version'); // Next (preview) label is mapped to v8 here - const themeTag = `${themeVersion === 'v7' ? 'v7' : 'v8'}${darkMode ? 'dark' : 'light'}`; + const themeTag = `${themeVersion}${themeMode}`; const buildHash = server.newPlatform.env.packageInfo.buildNum; const basePath = config.get('server.basePath'); @@ -112,25 +117,9 @@ export function uiRenderMixin(osdServer, server, config) { const styleSheetPaths = [ `${regularBundlePath}/osd-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`, - ...(darkMode - ? [ - themeVersion === 'v7' - ? `${regularBundlePath}/osd-ui-shared-deps/${UiSharedDeps.darkCssDistFilename}` - : `${regularBundlePath}/osd-ui-shared-deps/${UiSharedDeps.darkV8CssDistFilename}`, - themeVersion === 'v7' - ? `${basePath}/node_modules/@osd/ui-framework/dist/kui_dark.css` - : `${basePath}/node_modules/@osd/ui-framework/dist/kui_next_dark.css`, - `${basePath}/ui/legacy_dark_theme.css`, - ] - : [ - themeVersion === 'v7' - ? `${regularBundlePath}/osd-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}` - : `${regularBundlePath}/osd-ui-shared-deps/${UiSharedDeps.lightV8CssDistFilename}`, - themeVersion === 'v7' - ? `${basePath}/node_modules/@osd/ui-framework/dist/kui_light.css` - : `${basePath}/node_modules/@osd/ui-framework/dist/kui_next_light.css`, - `${basePath}/ui/legacy_light_theme.css`, - ]), + `${regularBundlePath}/osd-ui-shared-deps/${UiSharedDeps.themeCssDistFilenames[themeVersion][themeMode]}`, + `${basePath}/node_modules/@osd/ui-framework/dist/${UiSharedDeps.kuiCssDistFilenames[themeVersion][themeMode]}`, + `${basePath}/ui/legacy_${themeMode}_theme.css`, ]; const kpUiPlugins = osdServer.newPlatform.__internals.uiPlugins; diff --git a/src/plugins/advanced_settings/public/header_user_theme_menu.tsx b/src/plugins/advanced_settings/public/header_user_theme_menu.tsx index fc297aaa74bc..b1d6f09dafff 100644 --- a/src/plugins/advanced_settings/public/header_user_theme_menu.tsx +++ b/src/plugins/advanced_settings/public/header_user_theme_menu.tsx @@ -21,23 +21,17 @@ import { EuiButtonIcon, } from '@elastic/eui'; import { CoreStart } from 'opensearch-dashboards/public'; +import { themeVersionLabelMap, themeVersionValueMap } from '@osd/ui-shared-deps/theme_config'; import { useOpenSearchDashboards, useUiSetting$ } from '../../opensearch_dashboards_react/public'; export const HeaderUserThemeMenu = () => { const { services: { uiSettings }, } = useOpenSearchDashboards(); - // TODO: move to central location? - const themeOptions = [ - { - value: 'v7', - text: 'v7', - }, - { - value: 'next', - text: 'Next (preview)', - }, - ]; + const themeOptions = Object.keys(themeVersionLabelMap).map((v) => ({ + value: v, + text: themeVersionLabelMap[v], + })); const screenModeOptions = [ { value: 'light', @@ -52,13 +46,18 @@ export const HeaderUserThemeMenu = () => { text: 'Use browser settings', }, ]; + const defaultTheme = uiSettings.getDefault('theme:version'); + const defaultScreenMode = uiSettings.getDefault('theme:darkMode'); const prefersAutomatic = (window.localStorage.getItem('useBrowserColorScheme') && window.matchMedia) || false; const [darkMode, setDarkMode] = useUiSetting$('theme:darkMode'); const [themeVersion, setThemeVersion] = useUiSetting$('theme:version'); const [isPopoverOpen, setPopover] = useState(false); // TODO: improve naming? - const [theme, setTheme] = useState(themeOptions.find((t) => t.text === themeVersion)?.value); + const [theme, setTheme] = useState( + themeOptions.find((t) => t.value === themeVersionValueMap[themeVersion])?.value || + themeVersionValueMap[defaultTheme] + ); const [screenMode, setScreenMode] = useState( prefersAutomatic ? screenModeOptions[2].value @@ -66,9 +65,6 @@ export const HeaderUserThemeMenu = () => { ? screenModeOptions[1].value : screenModeOptions[0].value ); - const allSettings = uiSettings.getAll(); - const defaultTheme = allSettings['theme:version'].value; - const defaultScreenMode = allSettings['theme:darkMode'].value; const legacyAppearance = !uiSettings.get('home:useNewHomePage'); @@ -85,7 +81,7 @@ export const HeaderUserThemeMenu = () => { }; const onAppearanceSubmit = async (e: SyntheticEvent) => { - const actions = [setThemeVersion(themeOptions.find((t) => theme === t.value)?.text ?? '')]; + const actions = [setThemeVersion(themeOptions.find((t) => theme === t.value)?.value ?? '')]; if (screenMode === 'automatic') { const browserMode = window.matchMedia('(prefers-color-scheme: dark)').matches; diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap index 62bb2f9e90fc..6c8cbf7bd5aa 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap @@ -929,6 +929,7 @@ exports[`Dashboard top nav render in embed mode 1`] = ` }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], @@ -1985,6 +1986,7 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], @@ -3041,6 +3043,7 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], @@ -4097,6 +4100,7 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], @@ -5153,6 +5157,7 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], @@ -6209,6 +6214,7 @@ exports[`Dashboard top nav render with all components 1`] = ` }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], diff --git a/src/plugins/dashboard/public/application/embeddable/empty/__snapshots__/dashboard_empty_screen.test.tsx.snap b/src/plugins/dashboard/public/application/embeddable/empty/__snapshots__/dashboard_empty_screen.test.tsx.snap index 3e910f5dc4f9..9889462a0472 100644 --- a/src/plugins/dashboard/public/application/embeddable/empty/__snapshots__/dashboard_empty_screen.test.tsx.snap +++ b/src/plugins/dashboard/public/application/embeddable/empty/__snapshots__/dashboard_empty_screen.test.tsx.snap @@ -173,6 +173,7 @@ exports[`DashboardEmptyScreen renders correctly with readonly mode 1`] = ` }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], @@ -520,6 +521,7 @@ exports[`DashboardEmptyScreen renders correctly with visualize paragraph 1`] = ` }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], @@ -906,6 +908,7 @@ exports[`DashboardEmptyScreen renders correctly without visualize paragraph 1`] }, "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], diff --git a/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap b/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap index 00dd4ef65d32..41755d0462a8 100644 --- a/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap +++ b/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap @@ -465,6 +465,7 @@ exports[`LanguageSelector should select DQL if language is kuery 1`] = ` "get": [MockFunction], "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], @@ -1032,6 +1033,7 @@ exports[`LanguageSelector should select lucene if language is lucene 1`] = ` "get": [MockFunction], "get$": [MockFunction], "getAll": [MockFunction], + "getDefault": [MockFunction], "getSaved$": [MockFunction], "getUpdate$": [MockFunction], "getUpdateErrors$": [MockFunction], From 4a7375b5df3e791088d6c900e98d1821c9886788 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Tue, 20 Aug 2024 00:08:55 +0800 Subject: [PATCH 207/276] [navigation] Left navigation collective (#7655) (#7728) * feat: change nav groups Signed-off-by: SuZhou-Joe * Changeset file for PR #7655 created/updated * feat: move visualizations to all use case Signed-off-by: SuZhou-Joe * feat: change the scrollable area Signed-off-by: SuZhou-Joe * feat: register manage workspace category when in a workspace Signed-off-by: SuZhou-Joe * feat: register index patterns to settings and setup Signed-off-by: SuZhou-Joe * feat: show correct icon in top Signed-off-by: SuZhou-Joe * feat: use gap to replace margin Signed-off-by: SuZhou-Joe * feat: make new left nav work in mobile mode Signed-off-by: SuZhou-Joe * fix: bootstrap error Signed-off-by: SuZhou-Joe * fix: unit test error Signed-off-by: SuZhou-Joe * feat: justify content Signed-off-by: SuZhou-Joe * fix: unit test Signed-off-by: SuZhou-Joe * fix: unit test Signed-off-by: SuZhou-Joe * feat: add descriptions to core features Signed-off-by: SuZhou-Joe * feat: add description to index pattern Signed-off-by: SuZhou-Joe * feat: use smaller font size in left nav Signed-off-by: SuZhou-Joe * feat: append navLinks inside second level to custom category if no entry for the nav group Signed-off-by: SuZhou-Joe * feat: some optimize Signed-off-by: SuZhou-Joe * feat: optimize code Signed-off-by: SuZhou-Joe * feat: fix unit test Signed-off-by: SuZhou-Joe * feat: filter all use case Signed-off-by: SuZhou-Joe * fix: unit test Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> (cherry picked from commit 6877beaadd517207722c261181c1751bfa5bfb40) --- changelogs/fragments/7655.yml | 2 + src/core/public/chrome/chrome_service.tsx | 1 + ...ollapsible_nav_group_enabled.test.tsx.snap | 461 +++++++++--------- .../header/__snapshots__/header.test.tsx.snap | 55 +++ .../header/collapsible_nav_group_enabled.scss | 15 +- .../collapsible_nav_group_enabled.test.tsx | 119 +++-- .../header/collapsible_nav_group_enabled.tsx | 104 ++-- ...collapsible_nav_group_enabled_top.test.tsx | 132 ++--- .../collapsible_nav_group_enabled_top.tsx | 88 ++-- .../public/chrome/ui/header/header.test.tsx | 2 + src/core/public/chrome/ui/header/header.tsx | 4 +- src/core/utils/default_app_categories.ts | 7 + src/core/utils/default_nav_groups.ts | 1 - .../advanced_settings/public/plugin.ts | 3 + .../data_source_management/public/plugin.ts | 49 +- src/plugins/home/public/plugin.ts | 26 +- .../public/plugin.test.ts | 2 +- .../index_pattern_management/public/plugin.ts | 46 +- src/plugins/management/public/plugin.ts | 18 +- .../saved_objects_management/public/plugin.ts | 48 +- src/plugins/visualize/public/plugin.ts | 7 + src/plugins/workspace/public/plugin.test.ts | 9 +- src/plugins/workspace/public/plugin.ts | 15 +- .../public/services/use_case_service.ts | 85 +++- src/plugins/workspace/public/utils.ts | 2 +- 25 files changed, 703 insertions(+), 598 deletions(-) create mode 100644 changelogs/fragments/7655.yml diff --git a/changelogs/fragments/7655.yml b/changelogs/fragments/7655.yml new file mode 100644 index 000000000000..70a921f4e6df --- /dev/null +++ b/changelogs/fragments/7655.yml @@ -0,0 +1,2 @@ +feat: +- [navigation] Left navigation collective ([#7655](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7655)) \ No newline at end of file diff --git a/src/core/public/chrome/chrome_service.tsx b/src/core/public/chrome/chrome_service.tsx index ef6d606aa0a5..10ef3f3a4e19 100644 --- a/src/core/public/chrome/chrome_service.tsx +++ b/src/core/public/chrome/chrome_service.tsx @@ -386,6 +386,7 @@ export class ChromeService { navGroupsMap$={navGroup.getNavGroupsMap$()} setCurrentNavGroup={navGroup.setCurrentNavGroup} workspaceList$={workspaces.workspaceList$} + currentWorkspace$={workspaces.currentWorkspace$} useUpdatedHeader={this.useUpdatedHeader} /> ), diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap index 2c6835acdaeb..95e501650f08 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap @@ -11,232 +11,232 @@ exports[` should render correctly 1`] = ` class="eui-fullHeight left-navigation-wrapper" >
+ +
+
- -
-
+
-
- - - + Observability +
-
+ +
+
- - -
- + - -
+ +
+
+
-
- - - + Essentials +
-
+ +
+
- - -
- + - -
+ +
- -
+
+

@@ -254,13 +254,8 @@ exports[` should render correctly 2`] = ` class="eui-fullHeight left-navigation-wrapper" >
-
-
+ class="flex-1-container" + />
@@ -283,62 +278,62 @@ exports[` should show all use case by default and class="eui-fullHeight left-navigation-wrapper" >
+ +
+
- -
-
- -
+
+

@@ -356,62 +351,62 @@ exports[` should show all use case when current na class="eui-fullHeight left-navigation-wrapper" >
+ +
+
- -
-
- -
+
+

@@ -424,7 +419,7 @@ exports[` should render correctly 1`] = ` class="euiFlexItem" >
@@ -298,84 +322,96 @@ exports[`Header should render without including system indices 1`] = ` className="euiSpacer euiSpacer--s" />
- -
-

- - multiple - , - "single": - filebeat-4-3-22 - , - "star": - filebeat-* - , + + +

+

+ + multiple + , + "single": + filebeat-4-3-22 + , + "star": + filebeat-* + , + } } - } - > - - An index pattern can match a single source, for example, - - - - - filebeat-4-3-22 - - - - - , or - - multiple - - data sources, - - + + An index pattern can match a single source, for example, + + + + + filebeat-4-3-22 + + + + + , or + + multiple + + data sources, + + + + + filebeat-* + + + + + . + + +
+ + - -

-
- + + + +

+
+
+
diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.test.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.test.tsx new file mode 100644 index 000000000000..f9b4efc7acb0 --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.test.tsx @@ -0,0 +1,18 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Description } from './description'; +import { mount } from 'enzyme'; +import React from 'react'; +import { mockManagementPlugin } from '../../../../mocks'; + +const mockContext = mockManagementPlugin.createIndexPatternManagmentContext(); + +describe('Description', () => { + it('render normally', () => { + const component = mount(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.tsx new file mode 100644 index 000000000000..cd6036f212ad --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/description.tsx @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { FormattedMessage } from '@osd/i18n/react'; +import { DocLinksStart } from 'opensearch-dashboards/public'; + +import { EuiText, EuiCode, EuiLink } from '@elastic/eui'; + +interface Props { + docLinks: DocLinksStart; +} + +export const Description = ({ docLinks }: Props) => ( + +

+ multiple, + single: filebeat-4-3-22, + star: filebeat-*, + }} + /> +
+ + + +

+
+); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/header.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/header.tsx index 5a0ab5018d2e..8e0ec8c4a8b8 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/header.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/header.tsx @@ -30,13 +30,13 @@ import React from 'react'; -import { EuiBetaBadge, EuiSpacer, EuiText, EuiCode, EuiLink } from '@elastic/eui'; +import { EuiBetaBadge, EuiSpacer, EuiText } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { FormattedMessage } from '@osd/i18n/react'; import { DocLinksStart } from 'opensearch-dashboards/public'; import { useOpenSearchDashboards } from '../../../../../../opensearch_dashboards_react/public'; import { IndexPatternManagmentContext } from '../../../../types'; +import { Description } from './description'; export const Header = ({ prompt, @@ -79,30 +79,7 @@ export const Header = ({ - -

- multiple, - single: filebeat-4-3-22, - star: filebeat-*, - }} - /> -
- - - -

-
+ {prompt ? ( <> diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/index.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/index.ts index 47ff6e19434b..1846268f1fa7 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/index.ts +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/header/index.ts @@ -29,3 +29,4 @@ */ export { Header } from './header'; +export { Description } from './description'; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx index 7795c20dafd5..a1f958e03075 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx @@ -182,4 +182,15 @@ describe('CreateIndexPatternWizard', () => { expect(clear).toBeCalledWith('1'); expect(routeComponentPropsMock.history.push).toBeCalledWith(`/patterns/1`); }); + + test('should render normally when use update UX', () => { + mockContext.uiSettings.get = () => true; + const component = createComponentWithContext( + CreateIndexPatternWizard, + { ...routeComponentPropsMock }, + mockContext + ); + + expect(component).toMatchSnapshot(); + }); }); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx index 337efa752aee..6f02c98aa4f8 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx @@ -42,7 +42,7 @@ import { withRouter, RouteComponentProps } from 'react-router-dom'; import { DocLinksStart } from 'src/core/public'; import { StepIndexPattern } from './components/step_index_pattern'; import { StepTimeField } from './components/step_time_field'; -import { Header } from './components/header'; +import { Header, Description } from './components/header'; import { LoadingState } from './components/loading_state'; import { context as contextType } from '../../../../opensearch_dashboards_react/public'; @@ -273,7 +273,14 @@ export class CreateIndexPatternWizard extends Component< } renderContent() { - const { allIndices, isInitiallyLoadingIndices, step, indexPattern, dataSourceRef } = this.state; + const { + allIndices, + isInitiallyLoadingIndices, + step, + indexPattern, + dataSourceRef, + docLinks, + } = this.state; const stepInfo = { totalStepNumber: this.totalSteps, @@ -281,6 +288,9 @@ export class CreateIndexPatternWizard extends Component< }; const hideLocalCluster = this.context.services.hideLocalCluster; + const useUpdatedUX = this.context.services.uiSettings.get('home:useNewHomePage'); + const { HeaderControl } = this.context.services.navigationUI; + const application = this.context.services.application; if (isInitiallyLoadingIndices) { return ; @@ -289,15 +299,30 @@ export class CreateIndexPatternWizard extends Component< const header = this.renderHeader(); if (step === DATA_SOURCE_STEP) { - return ( + const component = ( + + ); + return useUpdatedUX ? ( + <> + {component} + , + }, + ]} + setMountPoint={application.setAppDescriptionControls} + /> + + ) : ( {header} - + {component} ); } @@ -305,43 +330,74 @@ export class CreateIndexPatternWizard extends Component< if (step === INDEX_PATTERN_STEP) { const { location } = this.props; const initialQuery = new URLSearchParams(location.search).get('id') || undefined; - - return ( + const component = ( + + ); + return useUpdatedUX ? ( + <> + {/* Except StepDataSource, other components need to use PageContent to wrap when using new UX */} + {component} + , + }, + ]} + setMountPoint={application.setAppDescriptionControls} + /> + + ) : ( {header} - + {component} ); } if (step === TIME_FIELD_STEP) { - return ( + const component = ( + + ); + return useUpdatedUX ? ( + <> + {/* Except StepDataSource, other components need to use PageContent to wrap when using new UX */} + {component} + , + }, + ]} + setMountPoint={application.setAppDescriptionControls} + /> + + ) : ( {header} - + {component} ); } diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx index 76689ab7c553..a39dcd6cc5a2 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx @@ -101,6 +101,8 @@ export const EditIndexPattern = withRouter( chrome, data, docLinks, + navigationUI: { HeaderControl }, + application, } = useOpenSearchDashboards().services; const [fields, setFields] = useState(indexPattern.getNonScriptedFields()); const [conflictedFields, setConflictedFields] = useState( @@ -196,7 +198,99 @@ export const EditIndexPattern = withRouter( const showTagsSection = Boolean(indexPattern.timeFieldName || (tags && tags.length > 0)); - return ( + const useUpdatedUX = uiSettings.get('home:useNewHomePage'); + + const renderDescription = () => { + const component = ( + +

+ {indexPattern.title} }} + />{' '} + + {mappingAPILink} + +

+
+ ); + + return useUpdatedUX ? ( + + ) : ( + component + ); + }; + + const renderBadges = () => { + if (useUpdatedUX) { + const components = [ + ...(Boolean(indexPattern.timeFieldName) + ? [{timeFilterHeader}] + : []), + ...tags.map((tag: any) => {tag.name}), + ]; + const controls = components.map((component) => ({ + renderComponent: component, + })); + + return ( + + ); + } else { + return ( + + {Boolean(indexPattern.timeFieldName) && ( + + {timeFilterHeader} + + )} + {tags.map((tag: any) => ( + + {tag.name} + + ))} + + ); + } + }; + + return useUpdatedUX ? ( +
+ + {showTagsSection && renderBadges()} + {renderDescription()} + {conflictedFields.length > 0 && ( + <> + + +

{mappingConflictLabel}

+
+ + )} + +
+ ) : (
- {showTagsSection && ( - - {Boolean(indexPattern.timeFieldName) && ( - - {timeFilterHeader} - - )} - {tags.map((tag: any) => ( - - {tag.name} - - ))} - - )} + {showTagsSection && renderBadges()} - -

- {indexPattern.title} }} - />{' '} - - {mappingAPILink} - -

-
+ {renderDescription()} {conflictedFields.length > 0 && ( <> diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx index 386e0d840e1d..156a22f720f5 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx @@ -30,8 +30,18 @@ import React from 'react'; import { i18n } from '@osd/i18n'; -import { EuiFlexGroup, EuiToolTip, EuiFlexItem, EuiSmallButtonIcon, EuiText } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiToolTip, + EuiFlexItem, + EuiSmallButtonIcon, + EuiText, + EuiButtonIcon, + EuiButton, +} from '@elastic/eui'; import { IIndexPattern } from 'src/plugins/data/public'; +import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; +import { IndexPatternManagmentContext } from '../../../types'; interface IndexHeaderProps { indexPattern: IIndexPattern; @@ -78,7 +88,85 @@ export function IndexHeader({ refreshFields, deleteIndexPatternClick, }: IndexHeaderProps) { - return ( + const { + uiSettings, + navigationUI: { HeaderControl }, + application, + } = useOpenSearchDashboards().services; + + const useUpdatedUX = uiSettings.get('home:useNewHomePage'); + + return useUpdatedUX ? ( + + + + ), + }, + ] + : []), + ...(defaultIndex !== indexPattern.id && setDefault + ? [ + { + renderComponent: ( + + {i18n.translate( + 'indexPatternManagement.editIndexPattern.setDefaultButton.text', + { + defaultMessage: 'Set as default index', + } + )} + + ), + }, + ] + : []), + ...(refreshFields + ? [ + { + renderComponent: ( + + {i18n.translate( + 'indexPatternManagement.editIndexPattern.refreshFieldsButton.text', + { + defaultMessage: 'Refresh field list', + } + )} + + ), + }, + ] + : []), + ]} + setMountPoint={application.setAppRightControls} + /> + ) : ( diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx index 613958bd2a3c..fdceab0f5e59 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx @@ -39,6 +39,7 @@ import { EuiCompressedFieldSearch, EuiCompressedSelect, EuiSelectOption, + EuiPageContent, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { fieldWildcardMatcher } from '../../../../../opensearch_dashboards_utils/public'; @@ -125,6 +126,8 @@ export function Tabs({ indexPattern, saveIndexPattern, fields, history, location [uiSettings] ); + const useUpdatedUX = uiSettings.get('home:useNewHomePage'); + const getFilterSection = useCallback( (type: string) => { return ( @@ -174,63 +177,73 @@ export function Tabs({ indexPattern, saveIndexPattern, fields, history, location const getContent = useCallback( (type: string) => { + const Wrapper = useUpdatedUX ? EuiPageContent : Fragment; switch (type) { case TAB_INDEXED_FIELDS: return ( - - - {getFilterSection(type)} - - { - history.push(getPath(field, indexPattern)); - }, - getFieldInfo: indexPatternManagementStart.list.getFieldInfo, - }} - /> - + <> + {useUpdatedUX && } + + + {getFilterSection(type)} + + { + history.push(getPath(field, indexPattern)); + }, + getFieldInfo: indexPatternManagementStart.list.getFieldInfo, + }} + /> + + ); case TAB_SCRIPTED_FIELDS: return ( - - - {getFilterSection(type)} - - { - history.push(getPath(field, indexPattern)); - }, - }} - onRemoveField={refreshFilters} - painlessDocLink={docLinks.links.noDocumentation.scriptedFields.painless} - /> - + <> + {useUpdatedUX && } + + + {getFilterSection(type)} + + { + history.push(getPath(field, indexPattern)); + }, + }} + onRemoveField={refreshFilters} + painlessDocLink={docLinks.links.noDocumentation.scriptedFields.painless} + /> + + ); case TAB_SOURCE_FILTERS: return ( - - - {getFilterSection(type)} - - - + <> + {useUpdatedUX && } + + + {getFilterSection(type)} + + + + ); } }, @@ -247,6 +260,7 @@ export function Tabs({ indexPattern, saveIndexPattern, fields, history, location refreshFilters, scriptedFieldLanguageFilter, saveIndexPattern, + useUpdatedUX, ] ); diff --git a/src/plugins/index_pattern_management/public/mocks.ts b/src/plugins/index_pattern_management/public/mocks.ts index dacf876c2f6c..39731abf733b 100644 --- a/src/plugins/index_pattern_management/public/mocks.ts +++ b/src/plugins/index_pattern_management/public/mocks.ts @@ -126,6 +126,9 @@ const createIndexPatternManagmentContext = () => { data, indexPatternManagementStart: createStartContract(), setBreadcrumbs: () => {}, + navigationUI: { + HeaderControl: () => null, + }, }; }; diff --git a/src/plugins/management/public/components/management_app/management_app.tsx b/src/plugins/management/public/components/management_app/management_app.tsx index c30243563b01..1241bb571326 100644 --- a/src/plugins/management/public/components/management_app/management_app.tsx +++ b/src/plugins/management/public/components/management_app/management_app.tsx @@ -38,6 +38,7 @@ import { ManagementRouter } from './management_router'; import { ManagementSidebarNav } from '../management_sidebar_nav'; import { reactRouterNavigate } from '../../../../opensearch_dashboards_react/public'; import { SectionsServiceStart } from '../../types'; +import { CoreStart } from '../../../../../core/public'; import './management_app.scss'; @@ -52,6 +53,7 @@ export interface ManagementAppDependencies { opensearchDashboardsVersion: string; setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => void; hideInAppNavigation?: boolean; + uiSettings: CoreStart['uiSettings']; } export const ManagementApp = ({ dependencies, history }: ManagementAppProps) => { diff --git a/src/plugins/management/public/components/management_app/management_router.tsx b/src/plugins/management/public/components/management_app/management_router.tsx index 06c39570c7da..0e7ca593f69f 100644 --- a/src/plugins/management/public/components/management_app/management_router.tsx +++ b/src/plugins/management/public/components/management_app/management_router.tsx @@ -46,38 +46,46 @@ interface ManagementRouterProps { } export const ManagementRouter = memo( - ({ dependencies, history, setBreadcrumbs, onAppMounted, sections }: ManagementRouterProps) => ( - - - - {sections.map((section) => - section - .getAppsEnabled() - .map((app) => ( - ( - - )} - /> - )) - )} - ( - + ({ dependencies, history, setBreadcrumbs, onAppMounted, sections }: ManagementRouterProps) => { + const useUpdatedUX = dependencies.uiSettings.get('home:useNewHomePage'); + return ( + + + + {sections.map((section) => + section + .getAppsEnabled() + .map((app) => ( + ( + + )} + /> + )) )} - /> - - - - ) + ( + + )} + /> + + + + ); + } ); diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index 7b219bffad9e..00fd767b27fb 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -110,6 +110,7 @@ export class ManagementPlugin opensearchDashboardsVersion, setBreadcrumbs: coreStart.chrome.setBreadcrumbs, hideInAppNavigation, + uiSettings: coreStart.uiSettings, }); }, }); diff --git a/src/plugins/saved_objects_management/opensearch_dashboards.json b/src/plugins/saved_objects_management/opensearch_dashboards.json index 2802eb04b3dc..9a985345b030 100644 --- a/src/plugins/saved_objects_management/opensearch_dashboards.json +++ b/src/plugins/saved_objects_management/opensearch_dashboards.json @@ -3,7 +3,7 @@ "version": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["management", "data", "uiActions"], + "requiredPlugins": ["management", "data", "uiActions","navigation"], "optionalPlugins": [ "dashboard", "visualizations", diff --git a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx index 0c98f365b39d..e26956900627 100644 --- a/src/plugins/saved_objects_management/public/management_section/mount_section.tsx +++ b/src/plugins/saved_objects_management/public/management_section/mount_section.tsx @@ -64,7 +64,7 @@ export const mountManagementSection = async ({ dataSourceEnabled, dataSourceManagement, }: MountParams) => { - const [coreStart, { data, uiActions }, pluginStart] = await core.getStartServices(); + const [coreStart, { data, uiActions, navigation }, pluginStart] = await core.getStartServices(); const { element, history, setBreadcrumbs } = mountParams; if (allowedObjectTypes === undefined) { allowedObjectTypes = await getAllowedTypes(coreStart.http); @@ -89,6 +89,8 @@ export const mountManagementSection = async ({ return children! as React.ReactElement; }; + const useUpdatedUX = coreStart.uiSettings.get('home:useNewHomePage'); + const content = ( @@ -119,6 +121,8 @@ export const mountManagementSection = async ({ setBreadcrumbs={setBreadcrumbs} dataSourceEnabled={dataSourceEnabled} dataSourceManagement={dataSourceManagement} + navigation={navigation} + useUpdatedUX={useUpdatedUX} /> diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap index 877cc43a6383..010118f15481 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/__snapshots__/saved_objects_table.test.tsx.snap @@ -965,6 +965,51 @@ exports[`SavedObjectsTable should render normally 1`] = ` horizontalPosition="center" >
`; + +exports[`Header should render normally when useUpdatedUX is true 1`] = ` + + + + + , + }, + Object { + "renderComponent": + + , + }, + Object { + "renderComponent": + + , + }, + ] + } + setMountPoint={[MockFunction]} + /> + + + + + +`; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap index 6c14a3084527..c0537471afa3 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/table.test.tsx.snap @@ -26,6 +26,7 @@ exports[`Table prevents saved objects from being deleted 1`] = ` onChange={[Function]} toolsRight={ Array [ + , , , , + , + + + , + + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + isOpen={false} + ownFocus={true} + panelPaddingSize="s" + > + + } + labelType="label" + > + + } + name="includeReferencesDeep" + onChange={[Function]} + /> + + + + + + + , + ] + } + /> + +
+ +
+ +`; + +exports[`Table should render normally when use updated UX 1`] = ` + + + +
, , {}, + onImport: () => {}, + onRefresh: () => {}, + onDuplicate: () => {}, + objectCount: 4, + filteredCount: 2, + useUpdatedUX: false, + navigationUI: { HeaderControl: () => null, TopNavMenu: () => null }, + applications: applicationServiceMock.createStartContract(), +}; describe('Header', () => { it('should render normally', () => { const props = { - onExportAll: () => {}, - onImport: () => {}, - onRefresh: () => {}, - onDuplicate: () => {}, - objectCount: 4, - filteredCount: 2, + ...defaultProps, showDuplicateAll: false, }; @@ -51,12 +59,7 @@ describe('Header', () => { it('should render normally when showDuplicateAll is undefined', () => { const props = { - onExportAll: () => {}, - onImport: () => {}, - onRefresh: () => {}, - onDuplicate: () => {}, - objectCount: 4, - filteredCount: 2, + ...defaultProps, showDuplicateAll: undefined, }; @@ -64,17 +67,24 @@ describe('Header', () => { expect(component).toMatchSnapshot(); }); + + it('should render normally when useUpdatedUX is true', () => { + const props = { + ...defaultProps, + showDuplicateAll: true, + useUpdatedUX: true, + }; + + const component = shallow(
); + + expect(component).toMatchSnapshot(); + }); }); describe('Header - workspace enabled', () => { it('should render `Duplicate All` button when workspace enabled', () => { const props = { - onExportAll: () => {}, - onImport: () => {}, - onRefresh: () => {}, - onDuplicate: () => {}, - objectCount: 4, - filteredCount: 2, + ...defaultProps, showDuplicateAll: true, }; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx index f83cdfaf69f2..80f37d53ceec 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/header.tsx @@ -36,8 +36,12 @@ import { EuiText, EuiTextColor, EuiButtonEmpty, + EuiButton, } from '@elastic/eui'; import { FormattedMessage } from '@osd/i18n/react'; +import { ApplicationStart } from 'src/core/public'; +import { i18n } from '@osd/i18n'; +import { NavigationPublicPluginStart } from '../../../../../navigation/public'; export const Header = ({ onExportAll, @@ -46,6 +50,9 @@ export const Header = ({ onRefresh, objectCount, showDuplicateAll = false, + useUpdatedUX, + navigationUI: { HeaderControl }, + applications, }: { onExportAll: () => void; onImport: () => void; @@ -53,40 +60,72 @@ export const Header = ({ onRefresh: () => void; objectCount: number; showDuplicateAll: boolean; -}) => ( - - - - -

- -

-
-
+ useUpdatedUX: boolean; + navigationUI: NavigationPublicPluginStart['ui']; + applications: ApplicationStart; +}) => { + const title = useUpdatedUX ? null : ( + + +

+ +

+
+
+ ); + const description = useUpdatedUX ? ( + + ) : ( + +

+ + + +

+
+ ); - - - {showDuplicateAll && ( - - - - - - )} - - + + + ), + }, + ] + : []), + { + renderComponent: ( + - - - - + ), + }, + { + renderComponent: ( + - - + + ), + }, + ]} + setMountPoint={applications.setAppRightControls} + /> + ) : ( + + + {showDuplicateAll && ( - + - - - - - -

- - - -

-
- -
-); + )} + + + + + + + + + + + + + + + + + + ); + + return ( + + + {title} + {rightControls} + + + {description} + + + ); +}; diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx index e9b5595dd45d..ddf50e68c25a 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.test.tsx @@ -110,6 +110,7 @@ const defaultProps: TableProps = { onDuplicate: () => {}, onDuplicateSingle: () => {}, showDuplicate: false, + useUpdatedUX: false, }; describe('Table', () => { @@ -119,6 +120,16 @@ describe('Table', () => { expect(component).toMatchSnapshot(); }); + it('should render normally when use updated UX', () => { + const props = { + ...defaultProps, + useUpdatedUX: true, + }; + const component = shallowWithI18nProvider(); + + expect(component).toMatchSnapshot(); + }); + it('should render gotoApp link correctly for workspace', () => { const item = { id: 'dashboard-1', diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx index 1341461a800e..fdfd2cea2c28 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx @@ -47,6 +47,7 @@ import { EuiTableFieldDataColumnType, EuiTableActionsColumnType, EuiSearchBarProps, + EuiButtonIcon, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; @@ -90,6 +91,8 @@ export interface TableProps { availableWorkspaces?: WorkspaceAttribute[]; currentWorkspaceId?: string; showDuplicate: boolean; + useUpdatedUX: boolean; + onRefresh: () => void; } interface TableState { @@ -189,6 +192,8 @@ export class Table extends PureComponent { availableWorkspaces, currentWorkspaceId, showDuplicate, + useUpdatedUX, + onRefresh, } = this.props; const visibleWsIds = availableWorkspaces?.map((ws) => ws.id) || []; @@ -417,6 +422,17 @@ export class Table extends PureComponent { filters={filters} onChange={this.onChange} toolsRight={[ + <> + {useUpdatedUX && ( + + )} + , <>{showDuplicate && duplicateButton}, @@ -1185,6 +1198,8 @@ export class SavedObjectsTable extends Component diff --git a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx index 425baca096d2..f526f7f6c751 100644 --- a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx +++ b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx @@ -41,6 +41,7 @@ import { SavedObjectsManagementNamespaceServiceStart, } from '../services'; import { SavedObjectsTable } from './objects_table'; +import { NavigationPublicPluginStart } from '../../../navigation/public'; const SavedObjectsTablePage = ({ coreStart, @@ -53,6 +54,8 @@ const SavedObjectsTablePage = ({ setBreadcrumbs, dataSourceEnabled, dataSourceManagement, + navigation, + useUpdatedUX, }: { coreStart: CoreStart; dataStart: DataPublicPluginStart; @@ -64,6 +67,8 @@ const SavedObjectsTablePage = ({ setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; dataSourceEnabled: boolean; dataSourceManagement?: DataSourceManagementPluginSetup; + navigation: NavigationPublicPluginStart; + useUpdatedUX: boolean; }) => { const capabilities = coreStart.application.capabilities; const itemsPerPage = coreStart.uiSettings.get('savedObjects:perPage', 50); @@ -71,14 +76,20 @@ const SavedObjectsTablePage = ({ useEffect(() => { setBreadcrumbs([ - { - text: i18n.translate('savedObjectsManagement.breadcrumb.index', { - defaultMessage: 'Saved objects', - }), - href: '/', - }, + useUpdatedUX + ? { + text: i18n.translate('savedObjectsManagement.updatedUX.title', { + defaultMessage: 'Assets', + }), + } + : { + text: i18n.translate('savedObjectsManagement.breadcrumb.index', { + defaultMessage: 'Saved objects', + }), + href: '/', + }, ]); - }, [setBreadcrumbs]); + }, [setBreadcrumbs, useUpdatedUX]); return ( ); }; diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index 65c91d6ff14c..2f69c1587c65 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -67,6 +67,7 @@ import { DEFAULT_NAV_GROUPS } from '../../../core/public'; import { RecentWork } from './management_section/recent_work'; import { HOME_CONTENT_AREAS } from '../../../plugins/home/public'; import { getScopedBreadcrumbs } from '../../opensearch_dashboards_react/public'; +import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; /** * The id is used in src/plugins/workspace/public/plugin.ts and please change that accordingly if you change the id here. @@ -104,6 +105,7 @@ export interface StartDependencies { visBuilder?: VisBuilderStart; uiActions: UiActionsStart; contentManagement?: ContentManagementPluginStart; + navigation: NavigationPublicPluginStart; } export class SavedObjectsManagementPlugin From 006b820aca5af69b49e074f8a5b3a6b8d05493a1 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:26:05 +0800 Subject: [PATCH 211/276] fix ts type of injectSearchSourceReferences to avoid type casting (#7725) (#7762) (cherry picked from commit 85fae590022d837410d56c3d767386c5b1c48afe) Signed-off-by: Yulong Ruan Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../data/common/search/search_source/inject_references.ts | 2 +- .../public/saved_object/helpers/apply_opensearch_resp.ts | 5 +---- .../saved_visualizations/saved_visualization_references.ts | 2 +- .../saved_visualizations/saved_visualization_references.ts | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/plugins/data/common/search/search_source/inject_references.ts b/src/plugins/data/common/search/search_source/inject_references.ts index 286cfbd16c6e..c22da0089bc1 100644 --- a/src/plugins/data/common/search/search_source/inject_references.ts +++ b/src/plugins/data/common/search/search_source/inject_references.ts @@ -32,7 +32,7 @@ import { SavedObjectReference } from 'src/core/types'; import { SearchSourceFields } from './types'; export const injectReferences = ( - searchSourceFields: SearchSourceFields & { indexRefName: string }, + searchSourceFields: SearchSourceFields & { indexRefName?: string }, references: SavedObjectReference[] ) => { const searchSourceReturnFields: SearchSourceFields = { ...searchSourceFields }; diff --git a/src/plugins/saved_objects/public/saved_object/helpers/apply_opensearch_resp.ts b/src/plugins/saved_objects/public/saved_object/helpers/apply_opensearch_resp.ts index a7e864a49751..4fb92d87f432 100644 --- a/src/plugins/saved_objects/public/saved_object/helpers/apply_opensearch_resp.ts +++ b/src/plugins/saved_objects/public/saved_object/helpers/apply_opensearch_resp.ts @@ -91,10 +91,7 @@ export async function applyOpenSearchResp( let searchSourceValues = parseSearchSourceJSON(meta.searchSourceJSON); if (config.searchSource) { - searchSourceValues = injectSearchSourceReferences( - searchSourceValues as any, - resp.references - ); + searchSourceValues = injectSearchSourceReferences(searchSourceValues, resp.references); savedObject.searchSource = await dependencies.search.searchSource.create( searchSourceValues ); diff --git a/src/plugins/vis_builder/public/saved_visualizations/saved_visualization_references.ts b/src/plugins/vis_builder/public/saved_visualizations/saved_visualization_references.ts index 06710c4d0780..0381c5e015f1 100644 --- a/src/plugins/vis_builder/public/saved_visualizations/saved_visualization_references.ts +++ b/src/plugins/vis_builder/public/saved_visualizations/saved_visualization_references.ts @@ -13,7 +13,7 @@ export function injectReferences( ) { if (savedObject.searchSourceFields) { savedObject.searchSourceFields = injectSearchSourceReferences( - savedObject.searchSourceFields as any, + savedObject.searchSourceFields, references ); } diff --git a/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts b/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts index b0ee904273ab..78150615c32c 100644 --- a/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts +++ b/src/plugins/visualizations/public/saved_visualizations/saved_visualization_references.ts @@ -97,7 +97,7 @@ export function extractReferences({ export function injectReferences(savedObject: VisSavedObject, references: SavedObjectReference[]) { if (savedObject.searchSourceFields) { savedObject.searchSourceFields = injectSearchSourceReferences( - savedObject.searchSourceFields as any, + savedObject.searchSourceFields, references ); } From 1987d5c917b3e2646f64da85f9682d2a4dd90146 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 07:45:46 -0700 Subject: [PATCH 212/276] Revisit updated header spacing (#7741) (#7759) Also: * Bump OUI to 1.10.0 (cherry picked from commit 0a3bcd83b6b1787eac7b4329bdf390c2b6050c08) Signed-off-by: Miki Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- package.json | 2 +- packages/osd-ui-framework/package.json | 2 +- packages/osd-ui-shared-deps/package.json | 2 +- .../header/__snapshots__/header.test.tsx.snap | 306 ++++++++---------- .../__snapshots__/recent_items.test.tsx.snap | 34 +- src/core/public/chrome/ui/header/header.scss | 58 +++- src/core/public/chrome/ui/header/header.tsx | 12 +- .../ui/header/header_controls_container.scss | 22 +- .../public/chrome/ui/header/recent_items.scss | 16 +- .../public/chrome/ui/header/recent_items.tsx | 45 ++- .../ui/filter_bar/_global_filter_group.scss | 3 +- .../public/top_nav_menu/_index.scss | 8 + .../top_nav_menu/top_nav_control_item.tsx | 8 +- .../public/top_nav_menu/top_nav_menu.tsx | 6 +- .../plugins/osd_tp_run_pipeline/package.json | 2 +- .../osd_sample_panel_action/package.json | 2 +- .../osd_tp_custom_visualizations/package.json | 2 +- yarn.lock | 39 ++- 18 files changed, 306 insertions(+), 263 deletions(-) diff --git a/package.json b/package.json index 994bb6929218..0fc7f728ac39 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "dependencies": { "@aws-crypto/client-node": "^3.1.1", "@elastic/datemath": "5.0.3", - "@elastic/eui": "npm:@opensearch-project/oui@1.9.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", "@elastic/good": "^9.0.1-kibana3", "@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0", "@elastic/request-crypto": "2.0.0", diff --git a/packages/osd-ui-framework/package.json b/packages/osd-ui-framework/package.json index 74eb5c34c58b..3088d58f07ec 100644 --- a/packages/osd-ui-framework/package.json +++ b/packages/osd-ui-framework/package.json @@ -23,7 +23,7 @@ "enzyme-adapter-react-16": "^1.9.1" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.9.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", "@osd/babel-preset": "1.0.0", "@osd/optimizer": "1.0.0", "comment-stripper": "^0.0.4", diff --git a/packages/osd-ui-shared-deps/package.json b/packages/osd-ui-shared-deps/package.json index 23f05e9a2509..fc7da1d3b91f 100644 --- a/packages/osd-ui-shared-deps/package.json +++ b/packages/osd-ui-shared-deps/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@elastic/charts": "31.1.0", - "@elastic/eui": "npm:@opensearch-project/oui@1.9.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", "@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0", "@opensearch/datemath": "5.0.3", "@osd/i18n": "1.0.0", diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index 46dce92ddeac..219c5dd3d389 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -8923,17 +8923,23 @@ exports[`Header renders application header without title and breadcrumbs 1`] = ` - - + } closePopover={[Function]} display="inlineBlock" @@ -8950,86 +8956,61 @@ exports[`Header renders application header without title and breadcrumbs 1`] = `
- - - - - - - - - - , - } - } - className="euiHeaderSectionItemButton headerRecentItemsButton" - color="text" - data-test-subj="recentItemsSectionButton" - onClick={[Function]} - size="s" + - - - + aria-hidden="true" + className="euiButtonIcon__icon" + color="inherit" + data-euiicon-type="recent" + size="m" + /> + + + + +
@@ -17428,17 +17409,23 @@ exports[`Header renders page header with application title 1`] = ` - - + } closePopover={[Function]} display="inlineBlock" @@ -17455,86 +17442,61 @@ exports[`Header renders page header with application title 1`] = `
- - - - - - - - - - , - } - } - className="euiHeaderSectionItemButton headerRecentItemsButton" - color="text" - data-test-subj="recentItemsSectionButton" - onClick={[Function]} - size="xs" + - - - + aria-hidden="true" + className="euiButtonIcon__icon" + color="inherit" + data-euiicon-type="recent" + size="m" + /> + + + + +
@@ -17807,22 +17769,22 @@ exports[`Header renders page header with application title 1`] = ` >
- -
+

-

- testTitle -

-
-
+ testTitle + +
- + aria-hidden="true" + class="euiButtonIcon__icon" + color="inherit" + data-euiicon-type="recent" + /> + + diff --git a/src/core/public/chrome/ui/header/header.scss b/src/core/public/chrome/ui/header/header.scss index 334bd76fbc4b..8828679e7284 100644 --- a/src/core/public/chrome/ui/header/header.scss +++ b/src/core/public/chrome/ui/header/header.scss @@ -5,24 +5,70 @@ .newTopNavHeader { z-index: 1000; - padding-left: $euiSizeXS; + padding: 0 $euiSizeL $euiSizeS; box-shadow: none; border-bottom: none; background: none; + height: auto; + gap: $euiSizeS; &.primaryHeader { - height: auto; - padding-top: $euiSizeM; + margin-top: $euiSizeM; } &.primaryApplicationHeader { - height: auto; padding-top: $euiSizeM - $euiSizeXS; + border-bottom: 1px solid $euiColorLightShade; + + &:last-child { + margin-bottom: 0; + } + } + + .headerAppActionMenu { + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors + & > .euiFlexGroup { + gap: $euiSizeS; + } + + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors + & > .euiHeaderLinks > .euiHeaderLinks__list { + gap: $euiSizeS; + + & > * { + margin: 0; + } + } } &:has(.headerDescriptionControl, .headerBottomControl) { height: auto; } + + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors + & > .euiHeaderSection { + gap: $euiSizeS; + + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors + & > .euiHeaderSectionItem:empty { + display: none; + } + } + + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors + &:not(:has(>:not(:empty))), + .euiHeaderSectionItem:not(:has(>:not(:empty))) { + display: none; + } +} + +.headerGlobalNav:has(.newTopNavHeader:not(.primaryApplicationHeader)) { + margin-bottom: -1 * $euiSizeS; +} + +.newTopNavHeaderTitle { + line-height: 1; + font-size: 2rem; } .primaryApplicationHeader { @@ -40,10 +86,6 @@ } } -.newTopNavApplicationTitle { - padding: 0 $euiSizeM; -} - .newAppTopNavExpander { position: fixed; left: 0; diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index 939a36911de9..492d9c7b3e78 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -36,7 +36,7 @@ import { EuiHideFor, EuiIcon, EuiShowFor, - EuiText, + EuiTitle, htmlIdGenerator, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; @@ -412,12 +412,10 @@ export function Header({ {/* Secondary header */} - - {breadcrumbs &&

{breadcrumbs[breadcrumbs.length - 1]?.text}

}
+ + + {breadcrumbs &&

{breadcrumbs[breadcrumbs.length - 1]?.text}

} +
{renderBadge()} diff --git a/src/core/public/chrome/ui/header/header_controls_container.scss b/src/core/public/chrome/ui/header/header_controls_container.scss index bba07ef60fbd..472dab2005de 100644 --- a/src/core/public/chrome/ui/header/header_controls_container.scss +++ b/src/core/public/chrome/ui/header/header_controls_container.scss @@ -4,19 +4,21 @@ */ .headerControl { - // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors - & > .euiHeaderSectionItem { - margin: 0 $euiSizeXS; - } + gap: $euiSizeS; &.headerDescriptionControl { - padding: 0 $euiSizeM; - color: $euiTextSubduedColor; - } + .descriptionHeaderControl { + max-width: $euiLegibilityMaxWidth; + line-height: 1.5; + color: $euiTextSubduedColor; - &.headerBottomControl { - padding: $euiSizeM; - max-width: 725px; + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors + .euiHeaderLink { + vertical-align: unset; + border: 0; + height: auto; + } + } } &:empty { diff --git a/src/core/public/chrome/ui/header/recent_items.scss b/src/core/public/chrome/ui/header/recent_items.scss index f8ba65393149..b82a533ca1c4 100644 --- a/src/core/public/chrome/ui/header/recent_items.scss +++ b/src/core/public/chrome/ui/header/recent_items.scss @@ -4,19 +4,7 @@ */ .headerRecentItemsButton { - margin-left: $euiSizeM; - margin-right: $euiSizeS; - min-width: $euiSizeL; - font-size: 0 !important; - - // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors - .euiHeaderSectionItemButton__content, - .euiButtonEmpty__text { - line-height: 1; - } - - // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors - .euiButtonEmpty__content { - padding: 0; + .primaryApplicationHeader & { + margin-top: $euiSizeXS; } } diff --git a/src/core/public/chrome/ui/header/recent_items.tsx b/src/core/public/chrome/ui/header/recent_items.tsx index 8224753dfd82..c7894104f163 100644 --- a/src/core/public/chrome/ui/header/recent_items.tsx +++ b/src/core/public/chrome/ui/header/recent_items.tsx @@ -6,16 +6,17 @@ import React, { useMemo, useState } from 'react'; import * as Rx from 'rxjs'; import { EuiPopover, - EuiHeaderSectionItemButton, EuiTextColor, EuiListGroup, EuiListGroupItem, EuiTitle, - EuiIcon, EuiText, EuiSpacer, EuiHeaderSectionItemButtonProps, + EuiButtonIcon, + EuiToolTip, } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; import useObservable from 'react-use/lib/useObservable'; import { ChromeRecentlyAccessedHistoryItem } from '../..'; import { WorkspaceObject } from '../../../workspace'; @@ -67,21 +68,35 @@ export const RecentItems = ({ setIsPopoverOpen(false); }; + const button = ( + + { + setIsPopoverOpen((prev) => !prev); + }} + data-test-subj="recentItemsSectionButton" + className="headerRecentItemsButton" + /> + + ); + return ( { - setIsPopoverOpen((prev) => !prev); - }} - data-test-subj="recentItemsSectionButton" - size={buttonSize} - className="headerRecentItemsButton" - > - {/* TODO: replace this icon once there is a new icon added to OUI https://github.com/opensearch-project/OpenSearch-Dashboards/issues/7354 */} - - - } + button={button} isOpen={isPopoverOpen} closePopover={() => { setIsPopoverOpen(false); diff --git a/src/plugins/data/public/ui/filter_bar/_global_filter_group.scss b/src/plugins/data/public/ui/filter_bar/_global_filter_group.scss index 96e6e4d6c97c..598d2f57b3a4 100644 --- a/src/plugins/data/public/ui/filter_bar/_global_filter_group.scss +++ b/src/plugins/data/public/ui/filter_bar/_global_filter_group.scss @@ -18,7 +18,8 @@ .headerAppActionMenu .globalQueryBar, .headerAppActionMenu .globalDatePicker { - padding-top: 0; + // The left-padding is a magic number just to add some space to the left that reduces with screen width + padding: 0 0 0 calc(100vw - 1600px); } .globalFilterGroup__filterBar { diff --git a/src/plugins/navigation/public/top_nav_menu/_index.scss b/src/plugins/navigation/public/top_nav_menu/_index.scss index 556b58ff6454..b8b2b7646eb3 100644 --- a/src/plugins/navigation/public/top_nav_menu/_index.scss +++ b/src/plugins/navigation/public/top_nav_menu/_index.scss @@ -2,11 +2,19 @@ .osdTopNavMenu { margin-right: $euiSizeXS; + + .newTopNavHeader & { + margin-right: 0; + } } .osdTopNavMenuGroupedActions { background-color: $euiColorEmptyShade; + .newTopNavHeader & { + margin: 0; + } + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors & > .euiSwitch, & > .euiButton, diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_control_item.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_control_item.tsx index 4b2d7b948170..fee4df701668 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_control_item.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_control_item.tsx @@ -52,7 +52,10 @@ export function TopNavControlItem(props: TopNavControlData) { {props.description} {links?.map((linkProps) => ( - + <> + {/* @ts-ignore using an undefined property to prevent abuse */} + + ))} ); @@ -102,7 +105,8 @@ export function TopNavControlItem(props: TopNavControlData) { case 'link': component = ( - + {screenTitle} @@ -187,7 +187,7 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { case TopNavMenuItemRenderType.OMITTED: return screenTitle ? ( - + {screenTitle} @@ -206,7 +206,7 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { return ( <> - + {screenTitle} diff --git a/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json b/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json index f7f34b3bf070..0764735d83c6 100644 --- a/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json +++ b/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json @@ -12,7 +12,7 @@ "build": "../../../../scripts/use_node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.9.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", "@osd/plugin-helpers": "1.0.0", "react": "^16.14.0", "react-dom": "^16.12.0", diff --git a/test/plugin_functional/plugins/osd_sample_panel_action/package.json b/test/plugin_functional/plugins/osd_sample_panel_action/package.json index acffe3bf4dc7..ceb81578a79b 100644 --- a/test/plugin_functional/plugins/osd_sample_panel_action/package.json +++ b/test/plugin_functional/plugins/osd_sample_panel_action/package.json @@ -12,7 +12,7 @@ "build": "../../../../scripts/use_node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.9.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", "react": "^16.14.0", "typescript": "4.0.2" } diff --git a/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json b/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json index 7e5deeb8955c..0726234c29a1 100644 --- a/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json +++ b/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json @@ -12,7 +12,7 @@ "build": "../../../../scripts/use_node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.9.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", "@osd/plugin-helpers": "1.0.0", "react": "^16.14.0", "typescript": "4.0.2" diff --git a/yarn.lock b/yarn.lock index 6ac8cb8ece0c..6be9df8a6e58 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1431,10 +1431,10 @@ resolved "https://registry.yarnpkg.com/@elastic/eslint-plugin-eui/-/eslint-plugin-eui-0.0.2.tgz#56b9ef03984a05cc213772ae3713ea8ef47b0314" integrity sha512-IoxURM5zraoQ7C8f+mJb9HYSENiZGgRVcG4tLQxE61yHNNRDXtGDWTZh8N1KIHcsqN1CEPETjuzBXkJYF/fDiQ== -"@elastic/eui@npm:@opensearch-project/oui@1.9.0": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@opensearch-project/oui/-/oui-1.9.0.tgz#c31ceffaf2a5e6dc9b51bc44eb8029f1dfd74a94" - integrity sha512-iHgS8HA5u2YdDI6IcesoO/wzeFdEiQwm51scGIJPvk+nxMyU2eX1s3SHs0xJd9gpNc2VSY97CgF6yK6tT52eUA== +"@elastic/eui@npm:@opensearch-project/oui@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@opensearch-project/oui/-/oui-1.10.0.tgz#111a400f5c04ba4088c0266bad7ab4306cc30d94" + integrity sha512-T1de6McK0YkXPjUUe0bYBHL58b7fJ43Bk/0ohpVn2ss5XkIPkFv7JE3diTCmr0cD1SsRfbM6lRNig4XBCOPflw== dependencies: "@types/chroma-js" "^2.4.0" "@types/react-beautiful-dnd" "^13.1.3" @@ -15689,7 +15689,7 @@ string-similarity@^4.0.1: resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -15724,6 +15724,15 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +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" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -15802,7 +15811,7 @@ stringify-entities@^3.0.1: character-entities-legacy "^1.0.0" xtend "^4.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -15844,6 +15853,13 @@ strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -17989,7 +18005,7 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -18015,6 +18031,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From c25a9658eeb7798d1ad6d774a49d97d778cb9cc4 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:05:35 -0700 Subject: [PATCH 213/276] Add an unified storage class for data plugin (#7701) (#7755) * add an unified storage class --------- (cherry picked from commit 9a842024809218413c8000f380fd90032a90ea03) Signed-off-by: abbyhu2000 Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- src/plugins/data/common/index.ts | 1 + src/plugins/data/common/storage/index.ts | 6 ++ src/plugins/data/common/storage/storage.ts | 68 +++++++++++++++++++ src/plugins/data/public/plugin.ts | 11 ++- .../data/public/query/lib/add_to_query_log.ts | 5 +- .../data/public/query/lib/get_query_log.ts | 5 +- .../query/persisted_log/persisted_log.ts | 6 +- .../data/public/query/query_service.ts | 12 ++-- .../query/query_string/query_history.ts | 64 +++++++++++++++++ .../query_string/query_string_manager.test.ts | 5 +- .../query_string/query_string_manager.ts | 31 +++++++-- .../state_sync/connect_to_query_state.test.ts | 19 +++--- .../state_sync/sync_state_with_url.test.ts | 14 ++-- .../public/query/timefilter/time_history.ts | 11 +-- .../query/timefilter/timefilter_service.ts | 5 +- src/plugins/data/public/types.ts | 4 +- .../ui/query_string_input/no_data_popover.tsx | 4 +- .../query_string_input/query_bar_top_row.tsx | 4 +- .../query_string_input.test.tsx | 5 +- .../query_string_input/query_string_input.tsx | 6 +- .../ui/search_bar/create_search_bar.tsx | 5 +- .../data/public/ui/search_bar/search_bar.tsx | 10 +++ .../data/public/ui/settings/settings.ts | 25 ++++--- src/plugins/data/public/ui/ui_service.ts | 4 +- 24 files changed, 245 insertions(+), 85 deletions(-) create mode 100644 src/plugins/data/common/storage/index.ts create mode 100644 src/plugins/data/common/storage/storage.ts create mode 100644 src/plugins/data/public/query/query_string/query_history.ts diff --git a/src/plugins/data/common/index.ts b/src/plugins/data/common/index.ts index 0250a6ec2e01..a10855a498cd 100644 --- a/src/plugins/data/common/index.ts +++ b/src/plugins/data/common/index.ts @@ -40,6 +40,7 @@ export * from './query'; export * from './search'; export * from './types'; export * from './utils'; +export * from './storage'; /** * Use data plugin interface instead diff --git a/src/plugins/data/common/storage/index.ts b/src/plugins/data/common/storage/index.ts new file mode 100644 index 000000000000..c37d921ee9d1 --- /dev/null +++ b/src/plugins/data/common/storage/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { DataStorage, createStorage } from './storage'; diff --git a/src/plugins/data/common/storage/storage.ts b/src/plugins/data/common/storage/storage.ts new file mode 100644 index 000000000000..8ec5f6a13b8d --- /dev/null +++ b/src/plugins/data/common/storage/storage.ts @@ -0,0 +1,68 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { transform, startsWith, keys } from 'lodash'; +import { parse, stringify } from '@osd/std'; + +export enum StorageKeys { + WIDTH = 'widths', +} + +type IStorageEngine = typeof window.localStorage; +export class DataStorage { + constructor(private readonly engine: IStorageEngine, private readonly prefix: string) {} + + encode(val: any) { + return stringify(val); + } + + decode(val: any) { + if (typeof val === 'string') { + return parse(val); + } + } + + encodeKey(key: string) { + return `${this.prefix}${key}`; + } + + decodeKey(key: string) { + if (startsWith(key, this.prefix)) { + return `${key.slice(this.prefix.length)}`; + } + } + + set(key: string, val: any) { + this.engine.setItem(this.encodeKey(key), this.encode(val)); + return val; + } + + has(key: string) { + return this.engine.getItem(this.encodeKey(key)) != null; + } + + get(key: string, _default?: T) { + if (this.has(key)) { + return this.decode(this.engine.getItem(this.encodeKey(key))); + } else { + return _default; + } + } + + remove(key: string) { + return this.engine.removeItem(this.encodeKey(key)); + } + + keys(): string[] { + return transform(keys(this.engine), (ours, key) => { + const ourKey = this.decodeKey(key); + if (ourKey != null) ours.push(ourKey); + }); + } +} + +export function createStorage(deps: { engine: IStorageEngine; prefix: string }) { + return new DataStorage(deps.engine, deps.prefix); +} diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index e204058fee4e..09bdd96d58e2 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -32,11 +32,7 @@ import './index.scss'; import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { ConfigSchema } from '../config'; -import { - Storage, - IStorageWrapper, - createStartServicesGetter, -} from '../../opensearch_dashboards_utils/public'; +import { createStartServicesGetter } from '../../opensearch_dashboards_utils/public'; import { DataPublicPluginSetup, DataPublicPluginStart, @@ -95,6 +91,7 @@ import { DefaultDslDataSource } from './data_sources/default_datasource'; import { DEFAULT_DATA_SOURCE_TYPE } from './data_sources/constants'; import { getSuggestions as getSQLSuggestions } from './antlr/opensearch_sql/code_completion'; import { getSuggestions as getDQLSuggestions } from './antlr/dql/code_completion'; +import { createStorage, DataStorage } from '../common'; declare module '../../ui_actions/public' { export interface ActionContextMapping { @@ -117,7 +114,7 @@ export class DataPublicPlugin private readonly uiService: UiService; private readonly fieldFormatsService: FieldFormatsService; private readonly queryService: QueryService; - private readonly storage: IStorageWrapper; + private readonly storage: DataStorage; constructor(initializerContext: PluginInitializerContext) { this.searchService = new SearchService(initializerContext); @@ -125,7 +122,7 @@ export class DataPublicPlugin this.queryService = new QueryService(); this.fieldFormatsService = new FieldFormatsService(); this.autocomplete = new AutocompleteService(initializerContext); - this.storage = new Storage(window.localStorage); + this.storage = createStorage({ engine: window.localStorage, prefix: 'opensearch_dashboards.' }); } public setup( diff --git a/src/plugins/data/public/query/lib/add_to_query_log.ts b/src/plugins/data/public/query/lib/add_to_query_log.ts index 206f18e31d84..038d2d4a2782 100644 --- a/src/plugins/data/public/query/lib/add_to_query_log.ts +++ b/src/plugins/data/public/query/lib/add_to_query_log.ts @@ -29,13 +29,12 @@ */ import { IUiSettingsClient } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; -import { Query } from '../../../common'; +import { DataStorage, Query } from '../../../common'; import { getQueryLog } from './get_query_log'; interface AddToQueryLogDependencies { uiSettings: IUiSettingsClient; - storage: IStorageWrapper; + storage: DataStorage; } export function createAddToQueryLog({ storage, uiSettings }: AddToQueryLogDependencies) { diff --git a/src/plugins/data/public/query/lib/get_query_log.ts b/src/plugins/data/public/query/lib/get_query_log.ts index aaf471f522cf..d2a4c7ccb551 100644 --- a/src/plugins/data/public/query/lib/get_query_log.ts +++ b/src/plugins/data/public/query/lib/get_query_log.ts @@ -29,14 +29,13 @@ */ import { IUiSettingsClient } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { PersistedLog } from '../persisted_log'; -import { UI_SETTINGS } from '../../../common'; +import { DataStorage, UI_SETTINGS } from '../../../common'; /** @internal */ export function getQueryLog( uiSettings: IUiSettingsClient, - storage: IStorageWrapper, + storage: DataStorage, appName: string, language: string ) { diff --git a/src/plugins/data/public/query/persisted_log/persisted_log.ts b/src/plugins/data/public/query/persisted_log/persisted_log.ts index 7b37ec51b736..ff230ee1ad09 100644 --- a/src/plugins/data/public/query/persisted_log/persisted_log.ts +++ b/src/plugins/data/public/query/persisted_log/persisted_log.ts @@ -31,7 +31,7 @@ import _ from 'lodash'; import * as Rx from 'rxjs'; import { map } from 'rxjs/operators'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; +import { DataStorage } from 'src/plugins/data/common'; const defaultIsDuplicate = (oldItem: any, newItem: any) => { return _.isEqual(oldItem, newItem); @@ -48,12 +48,12 @@ export class PersistedLog { public maxLength?: number; public filterDuplicates?: boolean; public isDuplicate: (oldItem: T, newItem: T) => boolean; - public storage: IStorageWrapper; + public storage: DataStorage; public items: T[]; private update$ = new Rx.BehaviorSubject(undefined); - constructor(name: string, options: PersistedLogOptions = {}, storage: IStorageWrapper) { + constructor(name: string, options: PersistedLogOptions = {}, storage: DataStorage) { this.name = name; this.maxLength = typeof options.maxLength === 'string' diff --git a/src/plugins/data/public/query/query_service.ts b/src/plugins/data/public/query/query_service.ts index 5c9c8b309367..17a7773567f3 100644 --- a/src/plugins/data/public/query/query_service.ts +++ b/src/plugins/data/public/query/query_service.ts @@ -30,7 +30,6 @@ import { share } from 'rxjs/operators'; import { IUiSettingsClient, SavedObjectsClientContract } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { FilterManager } from './filter_manager'; import { createAddToQueryLog } from './lib'; import { TimefilterService, TimefilterSetup } from './timefilter'; @@ -38,7 +37,12 @@ import { createSavedQueryService } from './saved_query/saved_query_service'; import { createQueryStateObservable } from './state_sync/create_global_query_observable'; import { QueryStringManager, QueryStringContract } from './query_string'; import { DataSetContract, DataSetManager } from './dataset_manager'; -import { buildOpenSearchQuery, getOpenSearchQueryConfig, IndexPatternsService } from '../../common'; +import { + buildOpenSearchQuery, + DataStorage, + getOpenSearchQueryConfig, + IndexPatternsService, +} from '../../common'; import { getUiSettings } from '../services'; import { IndexPattern } from '..'; @@ -48,13 +52,13 @@ import { IndexPattern } from '..'; */ interface QueryServiceSetupDependencies { - storage: IStorageWrapper; + storage: DataStorage; uiSettings: IUiSettingsClient; } interface QueryServiceStartDependencies { savedObjectsClient: SavedObjectsClientContract; - storage: IStorageWrapper; + storage: DataStorage; uiSettings: IUiSettingsClient; indexPatterns: IndexPatternsService; } diff --git a/src/plugins/data/public/query/query_string/query_history.ts b/src/plugins/data/public/query/query_string/query_history.ts new file mode 100644 index 000000000000..17e5f2cd1494 --- /dev/null +++ b/src/plugins/data/public/query/query_string/query_history.ts @@ -0,0 +1,64 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { DataStorage, SimpleDataSet } from 'src/plugins/data/common'; +import { BehaviorSubject } from 'rxjs'; +import { Query, TimeRange } from '../..'; + +// Todo: Implement a more advanced QueryHistory class when needed for recent query history +export class QueryHistory { + constructor(private readonly storage: DataStorage) {} + + private changeEmitter = new BehaviorSubject(this.getHistory() || []); + + getHistoryKeys() { + return this.storage + .keys() + .filter((key: string) => key.indexOf('query_') === 0) + .sort() + .reverse(); + } + + getHistory() { + return this.getHistoryKeys().map((key) => this.storage.get(key)); + } + + // This is used as an optimization mechanism so that different components + // can listen for changes to history and update because changes to history can + // be triggered from different places in the app. The alternative would be to store + // this in state so that we hook into the React model, but it would require loading history + // every time the application starts even if a user is not going to view history. + change(listener: (reqs: any[]) => void) { + const subscription = this.changeEmitter.subscribe(listener); + return () => subscription.unsubscribe(); + } + + addQueryToHistory(dataSet: SimpleDataSet, query: Query, dateRange?: TimeRange) { + const keys = this.getHistoryKeys(); + keys.splice(0, 500); // only maintain most recent X; + keys.forEach((key) => { + this.storage.remove(key); + }); + + const timestamp = new Date().getTime(); + const k = 'query_' + timestamp; + this.storage.set(k, { + dataSet, + time: timestamp, + query, + dateRange, + }); + + this.changeEmitter.next(this.getHistory()); + } + + clearHistory() { + this.getHistoryKeys().forEach((key) => this.storage.remove(key)); + } +} + +export function createHistory(deps: { storage: DataStorage }) { + return new QueryHistory(deps.storage); +} diff --git a/src/plugins/data/public/query/query_string/query_string_manager.test.ts b/src/plugins/data/public/query/query_string/query_string_manager.test.ts index 9def385c7dda..b9feb3be30d1 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.test.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.test.ts @@ -29,17 +29,16 @@ */ import { QueryStringManager } from './query_string_manager'; -import { Storage } from '../../../../opensearch_dashboards_utils/public/storage'; -import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; import { coreMock } from '../../../../../core/public/mocks'; import { Query } from '../../../common/query'; +import { DataStorage } from '../../../../data/common'; describe('QueryStringManager', () => { let service: QueryStringManager; beforeEach(() => { service = new QueryStringManager( - new Storage(new StubBrowserStorage()), + new DataStorage(window.localStorage, 'opensearch_dashboards.'), coreMock.createSetup().uiSettings ); }); diff --git a/src/plugins/data/public/query/query_string/query_string_manager.ts b/src/plugins/data/public/query/query_string/query_string_manager.ts index 3747cabaf9ca..98a348b58254 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.ts @@ -31,26 +31,28 @@ import { BehaviorSubject } from 'rxjs'; import { skip } from 'rxjs/operators'; import { CoreStart } from 'opensearch-dashboards/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; -import { Query, UI_SETTINGS } from '../../../common'; +import { DataStorage, Query, SimpleDataSet, TimeRange, UI_SETTINGS } from '../../../common'; +import { createHistory, QueryHistory } from './query_history'; export class QueryStringManager { private query$: BehaviorSubject; + private queryHistory: QueryHistory; constructor( - private readonly storage: IStorageWrapper, + private readonly storage: DataStorage, private readonly uiSettings: CoreStart['uiSettings'] ) { this.query$ = new BehaviorSubject(this.getDefaultQuery()); + this.queryHistory = createHistory({ storage }); } private getDefaultQueryString() { - return this.storage.get('opensearchDashboards.userQueryString') || ''; + return this.storage.get('userQueryString') || ''; } private getDefaultLanguage() { return ( - this.storage.get('opensearchDashboards.userQueryLanguage') || + this.storage.get('userQueryLanguage') || this.uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE) ); } @@ -100,6 +102,25 @@ export class QueryStringManager { public clearQuery = () => { this.setQuery(this.getDefaultQuery()); }; + + // Todo: update this function to use the Query object when it is udpated, Query object should include time range and dataset + public addToQueryHistory(dataSet: SimpleDataSet, query: Query, timeRange?: TimeRange) { + if (query.query) { + this.queryHistory.addQueryToHistory(dataSet, query, timeRange); + } + } + + public getQueryHistory() { + return this.queryHistory.getHistory(); + } + + public clearQueryHistory() { + this.queryHistory.clearHistory(); + } + + public changeQueryHistory(listener: (reqs: any[]) => void) { + return this.queryHistory.change(listener); + } } export type QueryStringContract = PublicMethodsOf; diff --git a/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts b/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts index fd73c589371e..17b9de0f4872 100644 --- a/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts +++ b/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts @@ -32,6 +32,7 @@ import { Subscription } from 'rxjs'; import { FilterManager } from '../filter_manager'; import { getFilter } from '../filter_manager/test_helpers/get_stub_filter'; import { + DataStorage, Filter, FilterStateStore, IndexPatternsService, @@ -44,10 +45,8 @@ import { createStateContainer, IOsdUrlStateStorage, createOsdUrlStateStorage, - Storage, } from '../../../../opensearch_dashboards_utils/public'; import { QueryService, QueryStart } from '../query_service'; -import { StubBrowserStorage } from '../../../../../test_utils/public/stub_browser_storage'; import { connectStorageToQueryState, connectToQueryState } from './connect_to_query_state'; import { TimefilterContract } from '../timefilter'; import { QueryState } from './types'; @@ -118,11 +117,11 @@ describe('connect_storage_to_query_state', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, indexPatterns: indexPatternsMock, }); @@ -226,11 +225,11 @@ describe('connect_to_global_state', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, indexPatterns: indexPatternsMock, }); @@ -464,11 +463,11 @@ describe('connect_to_app_state', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, indexPatterns: indexPatternsMock, }); @@ -647,11 +646,11 @@ describe('filters with different state', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, indexPatterns: indexPatternsMock, }); diff --git a/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts b/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts index 94c2ccc9a350..ca87637eb467 100644 --- a/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts +++ b/src/plugins/data/public/query/state_sync/sync_state_with_url.test.ts @@ -32,15 +32,19 @@ import { Subscription } from 'rxjs'; import { createBrowserHistory, History } from 'history'; import { FilterManager } from '../filter_manager'; import { getFilter } from '../filter_manager/test_helpers/get_stub_filter'; -import { Filter, FilterStateStore, IndexPatternsService, UI_SETTINGS } from '../../../common'; +import { + DataStorage, + Filter, + FilterStateStore, + IndexPatternsService, + UI_SETTINGS, +} from '../../../common'; import { coreMock } from '../../../../../core/public/mocks'; import { createOsdUrlStateStorage, IOsdUrlStateStorage, - Storage, } from '../../../../opensearch_dashboards_utils/public'; import { QueryService, QueryStart } from '../query_service'; -import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; import { TimefilterContract } from '../timefilter'; import { syncQueryStateWithUrl } from './sync_state_with_url'; import { QueryState } from './types'; @@ -94,12 +98,12 @@ describe('sync_query_state_with_url', () => { const queryService = new QueryService(); queryService.setup({ uiSettings: setupMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), }); queryServiceStart = queryService.start({ indexPatterns: indexPatternsMock, uiSettings: startMock.uiSettings, - storage: new Storage(new StubBrowserStorage()), + storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), savedObjectsClient: startMock.savedObjects.client, }); filterManager = queryServiceStart.filterManager; diff --git a/src/plugins/data/public/query/timefilter/time_history.ts b/src/plugins/data/public/query/timefilter/time_history.ts index b755fbf36da4..6c28892a0a05 100644 --- a/src/plugins/data/public/query/timefilter/time_history.ts +++ b/src/plugins/data/public/query/timefilter/time_history.ts @@ -29,14 +29,13 @@ */ import moment from 'moment'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { PersistedLog } from '../persisted_log'; -import { TimeRange } from '../../../common'; +import { DataStorage, TimeRange } from '../../../common'; export class TimeHistory { private history: PersistedLog; - constructor(storage: IStorageWrapper) { + constructor(storage: DataStorage) { const historyOptions = { maxLength: 10, filterDuplicates: true, @@ -44,11 +43,7 @@ export class TimeHistory { return oldItem.from === newItem.from && oldItem.to === newItem.to; }, }; - this.history = new PersistedLog( - 'opensearchDashboards.timepicker.timeHistory', - historyOptions, - storage - ); + this.history = new PersistedLog('timepicker.timeHistory', historyOptions, storage); } add(time: TimeRange) { diff --git a/src/plugins/data/public/query/timefilter/timefilter_service.ts b/src/plugins/data/public/query/timefilter/timefilter_service.ts index dbea62d46f89..b9bb0d3c3da0 100644 --- a/src/plugins/data/public/query/timefilter/timefilter_service.ts +++ b/src/plugins/data/public/query/timefilter/timefilter_service.ts @@ -29,9 +29,8 @@ */ import { IUiSettingsClient } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { TimeHistory, Timefilter, TimeHistoryContract, TimefilterContract } from './index'; -import { UI_SETTINGS } from '../../../common'; +import { DataStorage, UI_SETTINGS } from '../../../common'; /** * Filter Service @@ -40,7 +39,7 @@ import { UI_SETTINGS } from '../../../common'; export interface TimeFilterServiceDependencies { uiSettings: IUiSettingsClient; - storage: IStorageWrapper; + storage: DataStorage; } export class TimefilterService { diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 4f7936006a94..236ebfbb6e00 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -29,7 +29,6 @@ */ import { CoreStart } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { ExpressionsSetup } from 'src/plugins/expressions/public'; import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { AutocompleteSetup, AutocompleteStart } from './autocomplete'; @@ -41,6 +40,7 @@ import { IndexPatternsContract } from './index_patterns'; import { UsageCollectionSetup } from '../../usage_collection/public'; import { DataSourceStart } from './data_sources/datasource_services/types'; import { IUiStart, UiEnhancements } from './ui'; +import { DataStorage } from '../common'; export interface DataPublicPluginEnhancements { search?: SearchEnhancements; @@ -131,6 +131,6 @@ export interface IDataPluginServices extends Partial { savedObjects: CoreStart['savedObjects']; notifications: CoreStart['notifications']; http: CoreStart['http']; - storage: IStorageWrapper; + storage: DataStorage; data: DataPublicPluginStart; } diff --git a/src/plugins/data/public/ui/query_string_input/no_data_popover.tsx b/src/plugins/data/public/ui/query_string_input/no_data_popover.tsx index 73edbcc3a1d2..8fae21a7c4e2 100644 --- a/src/plugins/data/public/ui/query_string_input/no_data_popover.tsx +++ b/src/plugins/data/public/ui/query_string_input/no_data_popover.tsx @@ -31,8 +31,8 @@ import { ReactElement, useEffect, useState } from 'react'; import React from 'react'; import { EuiButtonEmpty, EuiText, EuiTourStep } from '@elastic/eui'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { i18n } from '@osd/i18n'; +import { DataStorage } from '../../../common'; const NO_DATA_POPOVER_STORAGE_KEY = 'data.noDataPopover'; @@ -42,7 +42,7 @@ export function NoDataPopover({ children, }: { showNoDataPopover?: boolean; - storage: IStorageWrapper; + storage: DataStorage; children: ReactElement; }) { const [noDataPopoverDismissed, setNoDataPopoverDismissed] = useState(() => diff --git a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx index f2679a6f5fc1..a14b044c6bae 100644 --- a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.tsx @@ -333,7 +333,7 @@ export default function QueryBarTopRow(props: QueryBarTopRowProps) { if ( language === 'kuery' && typeof query === 'string' && - (!storage || !storage.get('opensearchDashboards.luceneSyntaxWarningOptOut')) && + (!storage || !storage.get('luceneSyntaxWarningOptOut')) && doesKueryExpressionHaveLuceneSyntaxError(query) ) { const toast = notifications!.toasts.addWarning({ @@ -379,7 +379,7 @@ export default function QueryBarTopRow(props: QueryBarTopRowProps) { function onLuceneSyntaxWarningOptOut(toast: Toast) { if (!storage) return; - storage.set('opensearchDashboards.luceneSyntaxWarningOptOut', true); + storage.set('luceneSyntaxWarningOptOut', true); notifications!.toasts.remove(toast); } diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx index dfa5d57411d0..392071f0d10a 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx @@ -179,10 +179,7 @@ describe('QueryStringInput', () => { ); component.find(QueryLanguageSwitcher).props().onSelectLanguage('lucene'); - expect(mockStorage.set).toHaveBeenCalledWith( - 'opensearchDashboards.userQueryLanguage', - 'lucene' - ); + expect(mockStorage.set).toHaveBeenCalledWith('userQueryLanguage', 'lucene'); expect(mockCallback).toHaveBeenCalledWith({ query: '', language: 'lucene' }); }); diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index fed716bde2d2..62eca6bac579 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -381,13 +381,13 @@ export default class QueryStringInputUI extends Component { 'field' in suggestion && suggestion.field.subType && suggestion.field.subType.nested && - !this.services.storage.get('opensearchDashboards.DQLNestedQuerySyntaxInfoOptOut') + !this.services.storage.get('DQLNestedQuerySyntaxInfoOptOut') ) { const { notifications, docLinks } = this.services; const onDQLNestedQuerySyntaxInfoOptOut = (toast: Toast) => { if (!this.services.storage) return; - this.services.storage.set('opensearchDashboards.DQLNestedQuerySyntaxInfoOptOut', true); + this.services.storage.set('DQLNestedQuerySyntaxInfoOptOut', true); notifications!.toasts.remove(toast); }; @@ -469,7 +469,7 @@ export default class QueryStringInputUI extends Component { body: JSON.stringify({ opt_in: language === 'kuery' }), }); - this.services.storage.set('opensearchDashboards.userQueryLanguage', language); + this.services.storage.set('userQueryLanguage', language); const newQuery = { query: '', language }; this.onChange(newQuery); diff --git a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx index dc3d9191e056..675f6cdc5791 100644 --- a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx @@ -31,7 +31,6 @@ import _ from 'lodash'; import React, { useCallback, useEffect, useRef } from 'react'; import { CoreStart } from 'src/core/public'; -import { IStorageWrapper } from 'src/plugins/opensearch_dashboards_utils/public'; import { OpenSearchDashboardsContextProvider } from '../../../../opensearch_dashboards_react/public'; import { QueryStart, SavedQuery } from '../../query'; import { SearchBar, SearchBarOwnProps } from './'; @@ -39,14 +38,14 @@ import { useFilterManager } from './lib/use_filter_manager'; import { useTimefilter } from './lib/use_timefilter'; import { useSavedQuery } from './lib/use_saved_query'; import { DataPublicPluginStart } from '../../types'; -import { Filter, Query, TimeRange } from '../../../common'; +import { DataStorage, Filter, Query, TimeRange } from '../../../common'; import { useQueryStringManager } from './lib/use_query_string_manager'; import { Settings } from '../types'; interface StatefulSearchBarDeps { core: CoreStart; data: Omit; - storage: IStorageWrapper; + storage: DataStorage; settings: Settings; setDataSetContainerRef: (ref: HTMLDivElement | null) => void; } diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index 3db269074015..fd8ff3dc21c1 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -119,6 +119,8 @@ class SearchBarUI extends Component { }; private services = this.props.opensearchDashboards.services; + private dataSetService = this.services.data.query.dataSetManager; + private queryStringService = this.services.data.query.queryString; private savedQueryService = this.services.data.query.savedQueries; public filterBarRef: Element | null = null; public filterBarWrapperRef: Element | null = null; @@ -372,6 +374,14 @@ class SearchBarUI extends Component { } } ); + const dataSet = this.dataSetService.getDataSet(); + if (dataSet && queryAndDateRange.query) { + this.queryStringService.addToQueryHistory( + dataSet, + queryAndDateRange.query, + queryAndDateRange.dateRange + ); + } }; public onLoadSavedQuery = (savedQuery: SavedQuery) => { diff --git a/src/plugins/data/public/ui/settings/settings.ts b/src/plugins/data/public/ui/settings/settings.ts index 96c806ad0bc3..006d9c522cc1 100644 --- a/src/plugins/data/public/ui/settings/settings.ts +++ b/src/plugins/data/public/ui/settings/settings.ts @@ -4,8 +4,7 @@ */ import { BehaviorSubject } from 'rxjs'; -import { IStorageWrapper } from '../../../../opensearch_dashboards_utils/public'; -import { setOverrides as setFieldOverrides } from '../../../common'; +import { DataStorage, setOverrides as setFieldOverrides } from '../../../common'; import { ConfigSchema } from '../../../config'; import { ISearchStart } from '../../search'; import { QueryEditorExtensionConfig } from '../query_editor/query_editor_extensions'; @@ -31,7 +30,7 @@ export class Settings { constructor( private readonly config: ConfigSchema['enhancements'], private readonly search: ISearchStart, - private readonly storage: IStorageWrapper, + private readonly storage: DataStorage, private readonly queryEnhancements: Map, private readonly queryEditorExtensionMap: Record ) { @@ -72,26 +71,26 @@ export class Settings { } getUserQueryLanguageBlocklist() { - return this.storage.get('opensearchDashboards.userQueryLanguageBlocklist') || []; + return this.storage.get('userQueryLanguageBlocklist') || []; } setUserQueryLanguageBlocklist(languages: string[]) { this.storage.set( - 'opensearchDashboards.userQueryLanguageBlocklist', + 'userQueryLanguageBlocklist', languages.map((language) => language.toLowerCase()) ); return true; } getUserQueryLanguage() { - return this.storage.get('opensearchDashboards.userQueryLanguage') || 'kuery'; + return this.storage.get('userQueryLanguage') || 'kuery'; } setUserQueryLanguage(language: string) { if (language !== this.getUserQueryLanguage()) { this.search.df.clear(); } - this.storage.set('opensearchDashboards.userQueryLanguage', language); + this.storage.set('userQueryLanguage', language); const queryEnhancement = this.queryEnhancements.get(language); this.search.__enhance({ searchInterceptor: queryEnhancement @@ -104,25 +103,25 @@ export class Settings { } getUserQueryString() { - return this.storage.get('opensearchDashboards.userQueryString') || ''; + return this.storage.get('userQueryString') || ''; } setUserQueryString(query: string) { - this.storage.set('opensearchDashboards.userQueryString', query); + this.storage.set('userQueryString', query); return true; } getUiOverrides() { - return this.storage.get('opensearchDashboards.uiOverrides') || {}; + return this.storage.get('uiOverrides') || {}; } setUiOverrides(overrides?: { [key: string]: any }) { if (!overrides) { - this.storage.remove('opensearchDashboards.uiOverrides'); + this.storage.remove('uiOverrides'); setFieldOverrides(undefined); return true; } - this.storage.set('opensearchDashboards.uiOverrides', overrides); + this.storage.set('uiOverrides', overrides); setFieldOverrides(overrides.fields); return true; } @@ -155,7 +154,7 @@ export class Settings { interface Deps { config: ConfigSchema['enhancements']; search: ISearchStart; - storage: IStorageWrapper; + storage: DataStorage; queryEnhancements: Map; queryEditorExtensionMap: Record; } diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index 8359872137b2..1802e3b79320 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -5,7 +5,6 @@ import { BehaviorSubject } from 'rxjs'; import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public'; -import { IStorageWrapper } from '../../../opensearch_dashboards_utils/public'; import { ConfigSchema } from '../../config'; import { DataPublicPluginStart } from '../types'; import { createDataSetNavigator } from './dataset_navigator'; @@ -15,6 +14,7 @@ import { createSearchBar } from './search_bar/create_search_bar'; import { createSettings } from './settings'; import { SuggestionsComponent } from './typeahead'; import { IUiSetup, IUiStart, QueryEnhancement, UiEnhancements } from './types'; +import { DataStorage } from '../../common'; /** @internal */ // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -23,7 +23,7 @@ export interface UiServiceSetupDependencies {} /** @internal */ export interface UiServiceStartDependencies { dataServices: Omit; - storage: IStorageWrapper; + storage: DataStorage; } export class UiService implements Plugin { From 3835fc2748034268eb753ef9be1bcdb4d041b672 Mon Sep 17 00:00:00 2001 From: Viraj Sanghvi Date: Tue, 20 Aug 2024 15:56:50 -0700 Subject: [PATCH 214/276] [Manual Backport 2.x] feat: Add V9 Theme (#7757) (#7775) * feat: Add V9 Theme --------- Signed-off-by: Viraj Sanghvi Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> (cherry picked from commit 9d3ca7957a1c851d7b9a4fae8a2f1020a6c5fd9c) --- changelogs/fragments/7757.yml | 2 + docs/theme.md | 4 + .../core_app/styles/_globals_v9dark.scss | 1 + .../core_app/styles/_globals_v9light.scss | 1 + .../src/common/theme_tags.test.ts | 8 +- .../basic_optimization.test.ts.snap | 4 +- .../basic_optimization.test.ts | 4 +- .../src/optimizer/cache_keys.test.ts | 2 + packages/osd-ui-framework/Gruntfile.js | 2 + .../osd-ui-framework/dist/kui_v9_dark.css | 1635 +++++++++++++++++ .../osd-ui-framework/dist/kui_v9_light.css | 1635 +++++++++++++++++ .../osd-ui-framework/src/kui_v9_dark.scss | 15 + .../osd-ui-framework/src/kui_v9_light.scss | 15 + packages/osd-ui-shared-deps/theme.test.ts | 17 + packages/osd-ui-shared-deps/theme.ts | 3 + packages/osd-ui-shared-deps/theme_config.d.ts | 2 +- packages/osd-ui-shared-deps/theme_config.js | 2 + packages/osd-ui-shared-deps/webpack.config.js | 2 + .../core_app/styles/_globals_v9dark.scss | 7 + .../core_app/styles/_globals_v9light.scss | 7 + .../fira_code/FiraCode-VariableFont_wght.ttf | Bin 0 -> 259308 bytes .../assets/fonts/fira_code/LICENSE.txt | 93 + .../fonts/fira_code/static/FiraCode-Bold.ttf | Bin 0 -> 189152 bytes .../fira_code/static/FiraCode-Bold.woff2 | Bin 0 -> 69640 bytes .../fonts/fira_code/static/FiraCode-Light.ttf | Bin 0 -> 188708 bytes .../fira_code/static/FiraCode-Light.woff2 | Bin 0 -> 70060 bytes .../fira_code/static/FiraCode-Medium.ttf | Bin 0 -> 188492 bytes .../fira_code/static/FiraCode-Medium.woff2 | Bin 0 -> 70992 bytes .../fira_code/static/FiraCode-Regular.ttf | Bin 0 -> 188504 bytes .../fira_code/static/FiraCode-Regular.woff2 | Bin 0 -> 70700 bytes .../fira_code/static/FiraCode-SemiBold.ttf | Bin 0 -> 188848 bytes .../fira_code/static/FiraCode-SemiBold.woff2 | Bin 0 -> 71276 bytes .../server/core_app/assets/fonts/readme.md | 7 +- .../core_app/assets/fonts/rubik/LICENSE.txt | 93 + .../rubik/Rubik-Italic-VariableFont_wght.ttf | Bin 0 -> 351204 bytes .../fonts/rubik/Rubik-VariableFont_wght.ttf | Bin 0 -> 356080 bytes .../assets/fonts/rubik/static/Rubik-Black.ttf | Bin 0 -> 207836 bytes .../fonts/rubik/static/Rubik-Black.woff2 | Bin 0 -> 56572 bytes .../fonts/rubik/static/Rubik-BlackItalic.ttf | Bin 0 -> 206964 bytes .../rubik/static/Rubik-BlackItalic.woff2 | Bin 0 -> 57704 bytes .../assets/fonts/rubik/static/Rubik-Bold.ttf | Bin 0 -> 208320 bytes .../fonts/rubik/static/Rubik-Bold.woff2 | Bin 0 -> 61788 bytes .../fonts/rubik/static/Rubik-BoldItalic.ttf | Bin 0 -> 207204 bytes .../fonts/rubik/static/Rubik-BoldItalic.woff2 | Bin 0 -> 63004 bytes .../fonts/rubik/static/Rubik-ExtraBold.ttf | Bin 0 -> 208216 bytes .../fonts/rubik/static/Rubik-ExtraBold.woff2 | Bin 0 -> 61304 bytes .../rubik/static/Rubik-ExtraBoldItalic.ttf | Bin 0 -> 207340 bytes .../rubik/static/Rubik-ExtraBoldItalic.woff2 | Bin 0 -> 62660 bytes .../fonts/rubik/static/Rubik-Italic.ttf | Bin 0 -> 206344 bytes .../fonts/rubik/static/Rubik-Italic.woff2 | Bin 0 -> 62132 bytes .../assets/fonts/rubik/static/Rubik-Light.ttf | Bin 0 -> 206700 bytes .../fonts/rubik/static/Rubik-Light.woff2 | Bin 0 -> 55640 bytes .../fonts/rubik/static/Rubik-LightItalic.ttf | Bin 0 -> 205676 bytes .../rubik/static/Rubik-LightItalic.woff2 | Bin 0 -> 57044 bytes .../fonts/rubik/static/Rubik-Medium.ttf | Bin 0 -> 208204 bytes .../fonts/rubik/static/Rubik-Medium.woff2 | Bin 0 -> 61700 bytes .../fonts/rubik/static/Rubik-MediumItalic.ttf | Bin 0 -> 207052 bytes .../rubik/static/Rubik-MediumItalic.woff2 | Bin 0 -> 63064 bytes .../fonts/rubik/static/Rubik-Regular.ttf | Bin 0 -> 207632 bytes .../fonts/rubik/static/Rubik-Regular.woff2 | Bin 0 -> 61192 bytes .../fonts/rubik/static/Rubik-SemiBold.ttf | Bin 0 -> 208212 bytes .../fonts/rubik/static/Rubik-SemiBold.woff2 | Bin 0 -> 61500 bytes .../rubik/static/Rubik-SemiBoldItalic.ttf | Bin 0 -> 207188 bytes .../rubik/static/Rubik-SemiBoldItalic.woff2 | Bin 0 -> 63016 bytes src/core/server/rendering/views/fonts.tsx | 126 +- src/core/server/rendering/views/theme.ts | 4 + .../server/ui_settings/settings/theme.test.ts | 10 +- src/core/server/ui_settings/settings/theme.ts | 20 +- .../screenshots/baseline/area_chart.png | Bin 47504 -> 52095 bytes .../screenshots/baseline/tsvb_dashboard.png | Bin 48369 -> 47315 bytes 70 files changed, 3700 insertions(+), 21 deletions(-) create mode 100644 changelogs/fragments/7757.yml create mode 100644 packages/osd-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v9dark.scss create mode 100644 packages/osd-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v9light.scss create mode 100644 packages/osd-ui-framework/dist/kui_v9_dark.css create mode 100644 packages/osd-ui-framework/dist/kui_v9_light.css create mode 100644 packages/osd-ui-framework/src/kui_v9_dark.scss create mode 100644 packages/osd-ui-framework/src/kui_v9_light.scss create mode 100644 packages/osd-ui-shared-deps/theme.test.ts create mode 100644 src/core/public/core_app/styles/_globals_v9dark.scss create mode 100644 src/core/public/core_app/styles/_globals_v9light.scss create mode 100644 src/core/server/core_app/assets/fonts/fira_code/FiraCode-VariableFont_wght.ttf create mode 100644 src/core/server/core_app/assets/fonts/fira_code/LICENSE.txt create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Bold.ttf create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Bold.woff2 create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Light.ttf create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Light.woff2 create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Medium.ttf create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Medium.woff2 create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Regular.ttf create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Regular.woff2 create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-SemiBold.ttf create mode 100644 src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-SemiBold.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/LICENSE.txt create mode 100644 src/core/server/core_app/assets/fonts/rubik/Rubik-Italic-VariableFont_wght.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/Rubik-VariableFont_wght.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Black.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Black.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-BlackItalic.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-BlackItalic.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Bold.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Bold.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-BoldItalic.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-BoldItalic.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBold.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBold.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBoldItalic.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBoldItalic.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Italic.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Italic.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Light.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Light.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-LightItalic.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-LightItalic.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Medium.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Medium.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-MediumItalic.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-MediumItalic.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Regular.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-Regular.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBold.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBold.woff2 create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBoldItalic.ttf create mode 100644 src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBoldItalic.woff2 diff --git a/changelogs/fragments/7757.yml b/changelogs/fragments/7757.yml new file mode 100644 index 000000000000..0466de62dc13 --- /dev/null +++ b/changelogs/fragments/7757.yml @@ -0,0 +1,2 @@ +feat: +- Add v9 theme (preview) ([#7757](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7757)) \ No newline at end of file diff --git a/docs/theme.md b/docs/theme.md index 96873d1cbdff..cf85667e1d2d 100644 --- a/docs/theme.md +++ b/docs/theme.md @@ -160,3 +160,7 @@ Update `DEFAULT_THEME_VERSION` in `src/core/server/ui_settings/ui_settings_confi 1. Load variables for your theme in `THEME_SOURCES` 2. Define the text font for your theme in `fontText` 3. Define the code font for your theme in `fontCode` + 7. If on a branch without user specific themes: + 1. Update `THEME_SOURCES` in `src/core/server/rendering/views/theme.ts` + 2. Update `fontText` and `fontCode` in `src/core/server/rendering/views/fonts.tsx` + \ No newline at end of file diff --git a/packages/osd-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v9dark.scss b/packages/osd-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v9dark.scss new file mode 100644 index 000000000000..e5f1ee131499 --- /dev/null +++ b/packages/osd-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v9dark.scss @@ -0,0 +1 @@ +$globalStyleConstant: 14; diff --git a/packages/osd-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v9light.scss b/packages/osd-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v9light.scss new file mode 100644 index 000000000000..45d508715da0 --- /dev/null +++ b/packages/osd-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v9light.scss @@ -0,0 +1 @@ +$globalStyleConstant: 15; diff --git a/packages/osd-optimizer/src/common/theme_tags.test.ts b/packages/osd-optimizer/src/common/theme_tags.test.ts index 791734e9cfb6..ae8775484e7d 100644 --- a/packages/osd-optimizer/src/common/theme_tags.test.ts +++ b/packages/osd-optimizer/src/common/theme_tags.test.ts @@ -37,6 +37,8 @@ it('returns default tags when passed undefined', () => { "v7light", "v8dark", "v8light", + "v9dark", + "v9light", ] `); }); @@ -48,6 +50,8 @@ it('returns all tags when passed *', () => { "v7light", "v8dark", "v8light", + "v9dark", + "v9light", ] `); }); @@ -81,13 +85,13 @@ it('returns specific tags when passed an array', () => { it('throws when an invalid tag is in the array', () => { expect(() => parseThemeTags(['v8light', 'v7light', 'bar'])).toThrowErrorMatchingInlineSnapshot( - `"Invalid theme tags [bar], options: [v7dark, v7light, v8dark, v8light]"` + `"Invalid theme tags [bar], options: [v7dark, v7light, v8dark, v8light, v9dark, v9light]"` ); }); it('throws when an invalid tags in comma separated list', () => { expect(() => parseThemeTags('v8light ,v7light,bar,box ')).toThrowErrorMatchingInlineSnapshot( - `"Invalid theme tags [bar, box], options: [v7dark, v7light, v8dark, v8light]"` + `"Invalid theme tags [bar, box], options: [v7dark, v7light, v8dark, v8light, v9dark, v9light]"` ); }); diff --git a/packages/osd-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/osd-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap index dbbb5bad9bf3..776298aa496c 100644 --- a/packages/osd-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap +++ b/packages/osd-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -71,12 +71,14 @@ OptimizerConfig { "v7light", "v8dark", "v8light", + "v9dark", + "v9light", ], "watch": false, } `; -exports[`prepares assets for distribution: bar bundle 1`] = `"(function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports}var module=installedModules[moduleId]={i:moduleId,l:false,exports:{}};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{enumerable:true,get:getter})}};__webpack_require__.r=function(exports){if(typeof Symbol!==\\"undefined\\"&&Symbol.toStringTag){Object.defineProperty(exports,Symbol.toStringTag,{value:\\"Module\\"})}Object.defineProperty(exports,\\"__esModule\\",{value:true})};__webpack_require__.t=function(value,mode){if(mode&1)value=__webpack_require__(value);if(mode&8)return value;if(mode&4&&typeof value===\\"object\\"&&value&&value.__esModule)return value;var ns=Object.create(null);__webpack_require__.r(ns);Object.defineProperty(ns,\\"default\\",{enumerable:true,value:value});if(mode&2&&typeof value!=\\"string\\")for(var key in value)__webpack_require__.d(ns,key,function(key){return value[key]}.bind(null,key));return ns};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module[\\"default\\"]}:function getModuleExports(){return module};__webpack_require__.d(getter,\\"a\\",getter);return getter};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p=\\"\\";return __webpack_require__(__webpack_require__.s=3)})([function(module,exports,__webpack_require__){\\"use strict\\";module.exports=function(cssWithMappingToString){var list=[];list.toString=function toString(){return this.map((function(item){var content=cssWithMappingToString(item);if(item[2]){return\\"@media \\".concat(item[2],\\" {\\").concat(content,\\"}\\")}return content})).join(\\"\\")};list.i=function(modules,mediaQuery,dedupe){if(typeof modules===\\"string\\"){modules=[[null,modules,\\"\\"]]}var alreadyImportedModules={};if(dedupe){for(var i=0;i { bar.cache.refresh(); expect(bar.cache.getModuleCount()).toBe( // code + styles + style/css-loader runtimes + public path updater - 25 + 33 ); expect(bar.cache.getReferencedFiles()?.map(absolutePathSerializer.serialize).sort()) @@ -195,6 +195,8 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { "/packages/osd-optimizer/src/__fixtures__/__tmp__/mock_repo/src/core/public/core_app/styles/_globals_v7light.scss", "/packages/osd-optimizer/src/__fixtures__/__tmp__/mock_repo/src/core/public/core_app/styles/_globals_v8dark.scss", "/packages/osd-optimizer/src/__fixtures__/__tmp__/mock_repo/src/core/public/core_app/styles/_globals_v8light.scss", + "/packages/osd-optimizer/src/__fixtures__/__tmp__/mock_repo/src/core/public/core_app/styles/_globals_v9dark.scss", + "/packages/osd-optimizer/src/__fixtures__/__tmp__/mock_repo/src/core/public/core_app/styles/_globals_v9light.scss", "/packages/osd-optimizer/target/worker/entry_point_creator.js", "/packages/osd-ui-shared-deps/public_path_module_creator.js", ] diff --git a/packages/osd-optimizer/src/optimizer/cache_keys.test.ts b/packages/osd-optimizer/src/optimizer/cache_keys.test.ts index 5ca5c76a566f..95cd4b4b1d32 100644 --- a/packages/osd-optimizer/src/optimizer/cache_keys.test.ts +++ b/packages/osd-optimizer/src/optimizer/cache_keys.test.ts @@ -103,6 +103,8 @@ describe('getOptimizerCacheKey()', () => { "v7light", "v8dark", "v8light", + "v9dark", + "v9light", ], }, } diff --git a/packages/osd-ui-framework/Gruntfile.js b/packages/osd-ui-framework/Gruntfile.js index a0d8bd0abee8..e6c580f91bab 100644 --- a/packages/osd-ui-framework/Gruntfile.js +++ b/packages/osd-ui-framework/Gruntfile.js @@ -97,6 +97,8 @@ module.exports = function (grunt) { uiFrameworkCompile('src/kui_dark.scss', 'dist/kui_dark.css'), uiFrameworkCompile('src/kui_next_light.scss', 'dist/kui_next_light.css'), uiFrameworkCompile('src/kui_next_dark.scss', 'dist/kui_next_dark.css'), + uiFrameworkCompile('src/kui_v9_light.scss', 'dist/kui_v9_light.css'), + uiFrameworkCompile('src/kui_v9_dark.scss', 'dist/kui_v9_dark.css'), ]).then(done); }); }; diff --git a/packages/osd-ui-framework/dist/kui_v9_dark.css b/packages/osd-ui-framework/dist/kui_v9_dark.css new file mode 100644 index 000000000000..656f7facfc8b --- /dev/null +++ b/packages/osd-ui-framework/dist/kui_v9_dark.css @@ -0,0 +1,1635 @@ +/*! + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +main { + display: block; } + +.kuiBar { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 30px; } + +.kuiBarSection { + display: flex; + align-items: center; + flex: 1 1 auto; + margin-left: 25px; + margin-right: 25px; +} +.kuiBarSection:not(:first-child):not(:last-child):not(:only-child) { + justify-content: center; } +.kuiBarSection:first-child { + margin-left: 0; +} +.kuiBarSection:last-child { + margin-right: 0; + flex: 0 1 auto; justify-content: flex-end; } +.kuiBarSection:only-child { + margin-left: auto; } +.kuiBarSection > * + * { + margin-left: 10px; } + +.kuiButton { + display: inline-block; appearance: none; + cursor: pointer; + padding: 4px 12px 5px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + height: 30px; + text-decoration: none; + border: none; + border-radius: 4px; +} +.kuiButton:disabled { + cursor: not-allowed; + opacity: 0.5; +} +a.kuiButton.kuiButton-isDisabled { + cursor: not-allowed; + opacity: 0.5; +} + +.kuiButton:enabled:active { + transform: translateY(1px); +} +a.kuiButton:not(.kuiButton-isDisabled):active { transform: translateY(1px); +} + +.kuiButton__inner { + display: flex; align-items: center; } + +.kuiButton--small { + font-size: 12px; + padding: 2px 8px 3px; + height: 22px; +} + +.kuiButton--fullWidth { + width: 100%; + text-align: center; +} + +.kuiButton--iconText .kuiButton__icon:first-child:not(:only-child) { + margin-right: 8px; +} +.kuiButton--iconText .kuiButton__icon:last-child:not(:only-child) { + margin-left: 8px; +} +.kuiButton--iconText.kuiButton--small .kuiButton__icon:first-child:not(:only-child) { + margin-right: 4px; +} +.kuiButton--iconText.kuiButton--small .kuiButton__icon:last-child:not(:only-child) { + margin-left: 4px; +} + +.kuiButton--basic { + color: #DFE5EF; + background-color: #101B25; +} +.kuiButton--basic:not(a):enabled:focus { + color: #DFE5EF; +} +a.kuiButton--basic:not(.kuiButton-isDisabled):focus { color: #DFE5EF; +} + +.kuiButton--basic:enabled:hover { + background-color: #010101 !important; } +a.kuiButton--basic:not(.kuiButton-isDisabled):hover { background-color: #010101 !important; } + +.kuiButton--basic:enabled:active { + background-color: #010101 !important; } +a.kuiButton--basic:not(.kuiButton-isDisabled):active { background-color: #010101 !important; } + +.kuiButton--primary { + color: #FCFEFF; + background-color: #FFC0CB; +} +.kuiButton--primary:not(a):enabled:focus { + color: #FCFEFF; +} +a.kuiButton--primary:not(.kuiButton-isDisabled):focus { color: #FCFEFF; +} + +.kuiButton--primary:enabled:hover { + color: #FCFEFF !important; background-color: #ff8da1; +} +a.kuiButton--primary:not(.kuiButton-isDisabled):hover { color: #FCFEFF !important; background-color: #ff8da1; +} + +.kuiButton--primary:enabled:active { + color: #FCFEFF !important; background-color: #ff8da1; +} +a.kuiButton--primary:not(.kuiButton-isDisabled):active { color: #FCFEFF !important; background-color: #ff8da1; +} + +.kuiButton--success { + color: #FCFEFF; + background-color: #FFC0CB; +} +.kuiButton--success:not(a):enabled:focus { + color: #FCFEFF; +} +a.kuiButton--success:not(.kuiButton-isDisabled):focus { color: #FCFEFF; +} + +.kuiButton--success:enabled:hover { + color: #FCFEFF !important; background-color: #ff8da1; +} +a.kuiButton--success:not(.kuiButton-isDisabled):hover { color: #FCFEFF !important; background-color: #ff8da1; +} + +.kuiButton--success:enabled:active { + color: #FCFEFF !important; background-color: #ff8da1; +} +a.kuiButton--success:not(.kuiButton-isDisabled):active { color: #FCFEFF !important; background-color: #ff8da1; +} + +.kuiButton--danger { + color: #FF6666; + border: solid 1px #FF6666; +} +.kuiButton--danger:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #0A121A, 0 0 0 2px #FF6666; color: #FF6666; +} +a.kuiButton--danger:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #0A121A, 0 0 0 2px #FF6666; color: #FF6666; +} + +.kuiButton--danger:enabled:hover { + color: #ff3333 !important; + border: solid 1px #ff3333; + background-color: rgba(255, 102, 102, 0.1); +} +a.kuiButton--danger:not(.kuiButton-isDisabled):hover { color: #ff3333 !important; + border: solid 1px #ff3333; + background-color: rgba(255, 102, 102, 0.1); +} + +.kuiButton--danger:enabled:active { + color: #ff3333 !important; + border: solid 1px #ff3333; + background-color: rgba(255, 102, 102, 0.1); +} +a.kuiButton--danger:not(.kuiButton-isDisabled):active { color: #ff3333 !important; + border: solid 1px #ff3333; + background-color: rgba(255, 102, 102, 0.1); +} + +.kuiButton--warning { + color: #FCFEFF; + background-color: #FFCE7A; +} +.kuiButton--warning:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #0A121A, 0 0 0 2px #FFCE7A; color: #FCFEFF; +} +a.kuiButton--warning:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #0A121A, 0 0 0 2px #FFCE7A; color: #FCFEFF; +} + +.kuiButton--warning:enabled:hover { + color: #FCFEFF !important; background-color: #ffbb47; +} +a.kuiButton--warning:not(.kuiButton-isDisabled):hover { color: #FCFEFF !important; background-color: #ffbb47; +} + +.kuiButton--warning:enabled:active { + color: #FCFEFF !important; background-color: #ffbb47; +} +a.kuiButton--warning:not(.kuiButton-isDisabled):active { color: #FCFEFF !important; background-color: #ffbb47; +} + +.kuiButton--warning:disabled { + background-color: #ffe1ad; +} +a.kuiButton--warning.kuiButton-isDisabled { + background-color: #ffe1ad; +} + +.kuiButton--hollow { + color: #FFC0CB !important; background-color: transparent; +} +.kuiButton--hollow:enabled:hover { + color: #ff8da1 !important; text-decoration: underline; +} +a.kuiButton--hollow:not(.kuiButton-isDisabled):hover { color: #ff8da1 !important; text-decoration: underline; +} + +.kuiButton--hollow:enabled:active { + color: #ff8da1 !important; text-decoration: underline; +} +a.kuiButton--hollow:not(.kuiButton-isDisabled):active { color: #ff8da1 !important; text-decoration: underline; +} + +.kuiButton--secondary { + color: #FFC0CB !important; border: solid 1px #FFC0CB; +} +.kuiButton--secondary:enabled:hover { + color: #ff8da1 !important; border: solid 1px #ff8da1; + background-color: rgba(255, 192, 203, 0.1); + text-decoration: underline; +} +a.kuiButton--secondary:not(.kuiButton-isDisabled):hover { color: #ff8da1 !important; border: solid 1px #ff8da1; + background-color: rgba(255, 192, 203, 0.1); + text-decoration: underline; +} + +.kuiButton--secondary:enabled:active { + color: #ff8da1 !important; border: solid 1px #ff8da1; + background-color: rgba(255, 192, 203, 0.1); + text-decoration: underline; +} +a.kuiButton--secondary:not(.kuiButton-isDisabled):active { color: #ff8da1 !important; border: solid 1px #ff8da1; + background-color: rgba(255, 192, 203, 0.1); + text-decoration: underline; +} + +.kuiButtonGroup { + display: flex; + align-items: center; +} +.kuiButtonGroup .kuiButton + .kuiButton { + margin-left: 4px; +} + +.kuiButtonGroup--united > .kuiButton:not(:first-child):not(:last-child) { + border-radius: 0; +} +.kuiButtonGroup--united > .kuiButton:first-child { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.kuiButtonGroup--united > .kuiButton:last-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.kuiButtonGroup--united > .kuiButton:only-child { + border-radius: 4px 4px 4px 4px; +} +.kuiButtonGroup--united .kuiButton + .kuiButton { + margin-left: 0; +} + +.kuiButtonGroup--fullWidth { + display: flex; +} +.kuiButtonGroup--fullWidth > .kuiButton { + flex: 1 1 auto; + text-align: center; +} + +.eui-textCenter > .kuiButtonGroup, +.text-center > .kuiButtonGroup { + display: inline-block; +} + +.kuiCollapseButton { + appearance: none; + background-color: transparent; + padding: 4px; + border: none; + line-height: 1; + font-size: 16px; + color: #DFE5EF !important; cursor: pointer; + opacity: 0.35; +} +.kuiCollapseButton:hover { + opacity: 1; +} + +.kuiAssistedInput { + display: inline-block; position: relative; +} + +.kuiAssistedInput__assistance { + position: absolute; + right: 12px; + top: 50%; transform: translateY(-50%); } + +.kuiCheckBox { + appearance: none; background-color: #0e1721; + border: 1px solid rgba(252, 254, 255, 0.1); + border-radius: 4px; + width: 16px; + height: 16px; + font: var(--font-text) !important; line-height: 1.5 !important; margin: 0 !important; font-family: var(--font-text) !important; font-size: 10px !important; transition: background-color 0.1s linear; +} +.kuiCheckBox::before { + position: relative; + left: 0.25em; + font-family: FontAwesome, sans-serif; + content: "\f00c"; + font-size: 1em; + opacity: 0; + color: #FCFEFF; + transition: opacity 0.1s linear; +} +.kuiCheckBox:checked { + border-color: #FFC0CB; + background-color: #FFC0CB; +} +.kuiCheckBox:checked::before { + opacity: 1; +} +.kuiCheckBox:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #0A121A, 0 0 0 2px #FFC0CB; } +.kuiCheckBox:disabled { + background-color: #0d161e !important; + border-color: #0d161e !important; + cursor: not-allowed !important; +} + +.kuiCheckBoxLabel { + display: flex; + align-items: center; + font-weight: normal !important; + line-height: 1.5; +} + +.kuiCheckBoxLabel__text { + font-size: 16px; + margin-left: 8px; +} + +.kuiLabel { + font-size: 16px; + line-height: 1.5; + font-weight: bold; + margin-bottom: 0; } + +.kuiSearchInput { + width: 180px; + display: inline-block; + position: relative; + font-size: 16px; + line-height: 1.5; +} +.kuiSearchInput.kuiSearchInput-isInvalid .kuiSearchInput__input { + border-color: #FF6666; +} + +.kuiSearchInput__icon { + position: absolute; + top: 0.5em; + left: 0.7em; + font-size: 1em; + color: #5B6875; +} + +.kuiSearchInput__input { + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #DFE5EF; + background-color: #0e1721; + border: 1px solid rgba(252, 254, 255, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; padding-left: 28px; width: 100%; } +.kuiSearchInput__input:invalid { + border-color: #FF6666; +} +.kuiSearchInput__input:focus { + outline: none; + border-color: #FFC0CB; +} +.kuiSearchInput__input:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.kuiSearchInput--small { + width: 60px; +} + +.kuiSearchInput--large { + width: 400px; +} + +.kuiSelect { + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #DFE5EF; + background-color: #0e1721; + border: 1px solid rgba(252, 254, 255, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; padding-right: 30px; background-image: url('data:image/svg+xml;utf8,'); background-size: 14px; + background-repeat: no-repeat; + background-position: calc(100% - 8px); } +.kuiSelect:invalid { + border-color: #FF6666; +} +.kuiSelect:focus { + outline: none; + border-color: #FFC0CB; +} +.kuiSelect:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiSelect:-moz-focusring { + text-shadow: 0 0 0; } +.kuiSelect.kuiSelect-isInvalid { + border-color: #FF6666; +} +.kuiSelect:focus { + box-shadow: none; + outline: none; + border-color: #FFC0CB; +} + +.kuiSelect--small { + width: 60px; +} + +.kuiSelect--medium { + width: 180px; +} + +.kuiSelect--large { + width: 400px; +} + +.kuiStaticInput { + width: 180px; + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #DFE5EF; + border: 1px solid transparent; background-color: transparent; +} + +.kuiTextArea { + width: 180px; + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #DFE5EF; + background-color: #0e1721; + border: 1px solid rgba(252, 254, 255, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; } +.kuiTextArea:invalid { + border-color: #FF6666; +} +.kuiTextArea:focus { + outline: none; + border-color: #FFC0CB; +} +.kuiTextArea:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiTextArea:focus { + box-shadow: none; + outline: none; + border-color: #FFC0CB; +} +.kuiTextArea.kuiTextArea-isInvalid { + border-color: #FF6666; +} + +.kuiTextArea--nonResizable { + resize: none; +} + +.kuiTextArea--small { + width: 60px; +} + +.kuiTextArea--large { + width: 400px; +} + +.kuiTextInput { + width: 180px; + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #DFE5EF; + background-color: #0e1721; + border: 1px solid rgba(252, 254, 255, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; } +.kuiTextInput:invalid { + border-color: #FF6666; +} +.kuiTextInput:focus { + outline: none; + border-color: #FFC0CB; +} +.kuiTextInput:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiTextInput.kuiTextInput-isInvalid { + border-color: #FF6666; +} + +.kuiTextInput--small { + width: 60px; +} + +.kuiTextInput--large { + width: 400px; +} + +.kuiFieldGroup { + display: flex; + align-items: center; } + +.kuiFieldGroup--alignTop { + align-items: flex-start; +} + +.kuiFieldGroupSection { + line-height: 1.5; +} +.kuiFieldGroupSection + .kuiFieldGroupSection { + margin-left: 10px; +} + +.kuiFieldGroupSection--wide { + flex: 1 1 auto; +} +.kuiFieldGroupSection--wide > * { + width: 100%; +} + +.kuiIcon { + display: inline-block; font: normal normal normal 14px/1 FontAwesome, sans-serif; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } + +.kuiIcon--info { + color: #FFC0CB; +} + +.kuiIcon--success { + color: #FFC0CB; +} + +.kuiIcon--warning { + color: #FFCE7A; +} + +.kuiIcon--error { + color: #FF6666; +} + +.kuiIcon--inactive { + color: #293847; +} + +.kuiIcon--basic { + color: #8D98A3; +} + +.kuiInfoPanel { + padding: 14px 20px 18px; + line-height: 1.5; + border: 2px solid; +} + +.kuiInfoPanel--info { + border-color: rgba(255, 192, 203, 0.25); } + +.kuiInfoPanel--success { + border-color: rgba(255, 192, 203, 0.25); } + +.kuiInfoPanel--warning { + border-color: rgba(255, 206, 122, 0.25); } + +.kuiInfoPanel--error { + border-color: rgba(255, 102, 102, 0.25); } + +.kuiInfoPanelHeader { + display: flex; + align-items: baseline; } + +.kuiInfoPanelHeader__icon { + margin-right: 10px; + font-size: 16px; + line-height: 1.5; +} + +.kuiInfoPanelHeader__title { + font-size: 16px; + line-height: 1.5; + font-weight: 700; +} + +.kuiInfoPanelBody { + margin-top: 8px; +} +.kuiInfoPanelBody > * + * { + margin-top: 8px; +} + +.kuiInfoPanelBody__message { + font-size: 16px; + line-height: 1.5; +} + +.kuiLink { + color: #FFC0CB; + text-decoration: none; + cursor: pointer; appearance: none; background-color: transparent; border: none; font-size: inherit; line-height: inherit; } +.kuiLink:visited, .kuiLink:active { + color: #FFC0CB; +} +.kuiLink:hover { + color: #ff8da1; + text-decoration: underline; +} + +.kuiLocalBreadcrumbs { + display: flex; + align-items: center; + padding: 12px 8px; border-bottom: 1px solid #293847; + flex-grow: 1; + flex-basis: 100%; + background-color: #0A121A; +} + +.kuiLocalBreadcrumb { + font-size: 14px; + margin: 0; + font-weight: normal; +} +.kuiLocalBreadcrumb + .kuiLocalBreadcrumb { + margin-left: 6px; +} +.kuiLocalBreadcrumb + .kuiLocalBreadcrumb::before { + content: "/"; + user-select: none; + margin-right: 4px; + color: #293847; +} + +.kuiLocalBreadcrumb__link { + color: #FFC0CB; + text-decoration: none; + cursor: pointer; appearance: none; background-color: transparent; border: none; font-size: inherit; line-height: inherit; color: #FFC0CB; font-size: 16px; +} +.kuiLocalBreadcrumb__link:visited, .kuiLocalBreadcrumb__link:active { + color: #FFC0CB; +} +.kuiLocalBreadcrumb__link:hover { + color: #ff8da1; + text-decoration: underline; +} + +.kuiLocalBreadcrumb__emphasis { + font-weight: 700; +} + +.kuiDatePicker { + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; + line-height: 1.5; +} + +.kuiDatePickerNavigationCell { + padding: 0; +} + +.kuiDatePickerNavigation { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 4px; +} + +.kuiDatePickerNavigationButton { + appearance: none; + background-color: transparent; + border: none; + font-size: 14px; + color: #DFE5EF; + padding: 3px 6px; + border-radius: 4px; +} +.kuiDatePickerNavigationButton:hover, .kuiDatePickerNavigationButton:active { + cursor: pointer; + color: #101B25; + background-color: #FFC0CB; +} +.kuiDatePickerNavigationButton:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px transparent, 0 0 0 2px #FFC0CB; color: #DFE5EF; } + +.kuiDatePickerHeaderCell { + padding: 9px 0; + color: #DFE5EF; + font-size: 14px; + font-weight: bold; + text-align: center; + line-height: 1.2; +} + +.kuiDatePickerRowCell { + padding: 0; + text-align: center; +} + +.kuiDatePickerRowCellContent { + appearance: none; + background-color: transparent; + width: 100%; + border: 1px solid transparent; + color: #DFE5EF; + font-size: 14px; + padding: 8px; + border-radius: 4px; + line-height: 1.2; +} +.kuiDatePickerRowCellContent:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px transparent, 0 0 0 2px #FFC0CB; color: #DFE5EF; } +.kuiDatePickerRowCellContent:disabled { + pointer-events: none; + opacity: 0.5; +} +.kuiDatePickerRowCellContent.kuiDatePickerRowCellContent-isOtherMonth { + visibility: hidden; + pointer-events: none; +} +.kuiDatePickerRowCellContent.kuiDatePickerRowCellContent-isCurrent { + color: #FFC0CB; +} +.kuiDatePickerRowCellContent.kuiDatePickerRowCellContent-isSelected { + background-color: #8D98A3; + color: #DFE5EF; +} +.kuiDatePickerRowCellContent:hover, .kuiDatePickerRowCellContent:active { + cursor: pointer; + color: #101B25; + background-color: #FFC0CB; +} + +.kuiLocalDropdown { + position: relative; + padding: 10px 8px 14px; + background-color: transparent; + margin-bottom: 10px; + line-height: 20px; +} + +.kuiLocalDropdownCloseButton { + appearance: none; + background-color: transparent; + padding: 4px; + border: none; + line-height: 1; + font-size: 16px; + color: #DFE5EF !important; cursor: pointer; + opacity: 0.35; + position: absolute; + top: 1px; + right: 5px; +} +.kuiLocalDropdownCloseButton:hover { + opacity: 1; +} + +.kuiLocalDropdownPanels { + display: flex; +} + +.kuiLocalDropdownPanel { + flex: 1 1 0%; +} + +.kuiLocalDropdownPanel--left { + margin-right: 30px; +} + +.kuiLocalDropdownPanel--right { + margin-left: 30px; +} + +.kuiLocalDropdownTitle { + margin-top: 0; margin-bottom: 12px; + font-size: 18px; + color: #DFE5EF; +} + +.kuiLocalDropdownSection { + margin-bottom: 16px; +} +.kuiLocalDropdownSection:last-child { + margin-bottom: 0; +} + +.kuiLocalDropdownHeader { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 6px; +} + +.kuiLocalDropdownHeader__label { + font-size: 14px; + font-weight: 700; + margin-bottom: 0; color: #DFE5EF; +} + +.kuiLocalDropdownHeader__actions { + display: flex; +} + +.kuiLocalDropdownHeader__action { + color: #FFC0CB; + font-size: 12px; + text-decoration: none; + cursor: pointer; +} +.kuiLocalDropdownHeader__action + .kuiLocalDropdownHeader__action { + margin-left: 10px; +} +.kuiLocalDropdownHeader__action:hover, .kuiLocalDropdownHeader__action:active { + color: #ff8da1; +} + +.kuiLocalDropdownInput { + display: block; + width: 100%; + margin-bottom: 12px; + padding: 5px 15px; + font-size: 14px; + color: #DFE5EF; + background-color: #0e1721; + border: 1px solid rgba(252, 254, 255, 0.1); + border-radius: 4px; +} +.kuiLocalDropdownInput:focus { + border-color: #FFC0CB; +} + +.kuiLocalDropdownFormNote { + font-size: 14px; + color: #8D98A3; +} + +.kuiLocalDropdownWarning { + margin-bottom: 16px; + padding: 6px 10px; + font-size: 14px; + color: #DFE5EF; + background-color: #0A121A; + border-left: solid 2px #FF6666; +} + +.kuiLocalDropdownHelpText { + margin-bottom: 16px; + font-size: 14px; + color: #8D98A3; +} + +.kuiLocalMenu { + display: flex; + align-items: stretch; + padding-top: 8px; + padding-bottom: 8px; +} + +.kuiLocalMenuItem { + display: flex; + align-items: center; + padding: 2px 8px; + font-size: 16px; + background-color: transparent; + color: #DFE5EF; + border: 0; + cursor: pointer; + border-bottom: solid 2px transparent; +} +.kuiLocalMenuItem:hover, .kuiLocalMenuItem:focus { + background-color: rgba(255, 192, 203, 0.15); + text-decoration: underline; +} +.kuiLocalMenuItem.kuiLocalMenuItem-isSelected { + color: #FFC0CB; + background-color: transparent; + border-color: #FFC0CB; + z-index: 2; +} +.kuiLocalMenuItem.kuiLocalMenuItem-isSelected:hover, .kuiLocalMenuItem.kuiLocalMenuItem-isSelected:focus { + text-decoration: none; +} +.kuiLocalMenuItem.kuiLocalMenuItem-isDisabled { + opacity: 0.5; + cursor: not-allowed; +} +.kuiLocalMenuItem.kuiLocalMenuItem-isDisabled:hover { + background-color: transparent; + text-decoration: none; +} + +.kuiLocalMenuItem__icon { + margin-right: 5px; + margin-bottom: -1px; +} + +.kuiLocalNav { + display: flex; + flex-direction: column; + justify-content: space-between; + min-height: 69px; color: #DFE5EF; + background-color: #0A121A; + line-height: 1.5; + border-bottom: solid 1px #293847; +} + +.kuiLocalNavRow { + display: flex; + align-items: stretch; + justify-content: space-between; +} + +.kuiLocalNavRow__section { + display: flex; + align-items: stretch; +} + +.kuiLocalNavRow--secondary { + padding: 0 8px; align-items: flex-start; } + +.kuiLocalSearch { + display: flex; + width: 100%; + margin-bottom: 8px; +} + +.kuiLocalSearchInput { + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #DFE5EF; + background-color: #0e1721; + border: 1px solid rgba(252, 254, 255, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; flex: 1 1 100%; + border-color: #FCFEFF; + border-color: #293847; + border-radius: 4px 0 0 4px; +} +.kuiLocalSearchInput:invalid { + border-color: #FF6666; +} +.kuiLocalSearchInput:focus { + outline: none; + border-color: #FFC0CB; +} +.kuiLocalSearchInput:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiLocalSearchInput:focus { + box-shadow: none; +} +.kuiLocalSearchInput.kuiLocalSearchInput-isInvalid { + border-color: #FF6666; +} + +.kuiLocalSearchInput--secondary { + height: 32px; + flex: 0 0 auto; + border-radius: 0; + border-left-width: 0; +} + +.kuiLocalSearchInput, +.kuiLocalSearchAssistedInput__input { + padding-right: 6em; } + +.kuiLocalSearchAssistedInput__assistance { + position: absolute; + right: 6px; + top: 50%; z-index: 2; + transform: translateY(-50%); } + +.kuiLocalSearchSelect { + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #DFE5EF; + background-color: #0e1721; + border: 1px solid rgba(252, 254, 255, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; padding-right: 30px; background-image: url('data:image/svg+xml;utf8,'); background-size: 14px; + background-repeat: no-repeat; + background-position: calc(100% - 8px); border-left-width: 0; + border-radius: 0; +} +.kuiLocalSearchSelect:invalid { + border-color: #FF6666; +} +.kuiLocalSearchSelect:focus { + outline: none; + border-color: #FFC0CB; +} +.kuiLocalSearchSelect:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiLocalSearchSelect:-moz-focusring { + text-shadow: 0 0 0; } + +.kuiLocalSearchButton { + width: 43px; + height: 32px; + font-size: 16px; + line-height: 0; color: #FCFEFF; + background-color: #FFC0CB; + border: 0; + border-radius: 0 4px 4px 0; +} +.kuiLocalSearchButton:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FFC0CB; } + +.kuiLocalTabs { + display: flex; + align-items: flex-end; + height: 100%; +} + +.kuiLocalTab { + padding: 5px 0 6px; + font-size: 18px; + color: #DFE3E8; + border-bottom: 2px solid transparent; + text-decoration: none; + cursor: pointer; + margin-top: 0 !important; margin-bottom: 0 !important; } +.kuiLocalTab:hover:not(.kuiLocalTab-isDisabled), .kuiLocalTab:active:not(.kuiLocalTab-isDisabled) { + color: #FFC0CB; +} +.kuiLocalTab.kuiLocalTab-isSelected { + color: #FFC0CB; + border-bottom-color: #FFC0CB; + cursor: default; +} +.kuiLocalTab.kuiLocalTab-isDisabled { + opacity: 0.5; + cursor: default; } +.kuiLocalTab + .kuiLocalTab { + margin-left: 15px; +} + +.kuiLocalTitle { + display: flex; + align-items: center; + padding: 12px 8px; + font-size: 16px; + font-weight: bold; + border-bottom: 1px solid #293847; + flex-grow: 1; + flex-basis: 100%; + background-color: #0A121A; +} +.kuiLocalTitle:empty { + padding: 0; + display: none; +} + +.kuiPager { + display: flex; + align-items: center; +} +.kuiPager > * + * { + margin-left: 10px; } + +.kuiPagerText { + font-size: 16px; + line-height: 1.5; + color: #8D98A3; + white-space: nowrap; } + +.kuiPanel { + box-shadow: 0 2px 2px -1px rgba(0, 0, 0, 0.3), 0 1px 5px -2px rgba(0, 0, 0, 0.3); + background-color: #0A121A; + border: 1px solid #293847; + border-radius: 4px; +} + +.kuiPanel--prompt { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + justify-content: center; + min-height: 300px; +} +.kuiPanel--prompt .kuiPanelBody { + padding: 30px; + max-width: 500px; +} + +.kuiPanel--noBorder { + border: none; +} + +.kuiPanel--withToolBar { + border-top: none; + border-radius: 0; +} + +.kuiPanel--centered { + display: flex; + justify-content: center; + align-items: center; +} + +.kuiPanelHeader { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 30px; padding: 10px; + height: 50px; + border-bottom: 1px solid #293847; +} +.kuiPanelHeader .kuiButton:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FFC0CB; } +a.kuiPanelHeader .kuiButton:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FFC0CB; } + +.kuiPanelHeader .kuiButton--danger:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FF6666; } +a.kuiPanelHeader .kuiButton--danger:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FF6666; } + +.kuiPanelHeader .kuiSelect { + border-color: #0e1721; +} +.kuiPanelHeader .kuiSelect:not(a):enabled:focus { + outline: none; + border-color: #FFC0CB; +} +a.kuiPanelHeader .kuiSelect:not(.kuiButton-isDisabled):focus { outline: none; + border-color: #FFC0CB; +} + +.kuiPanelHeader__title { + font-size: 20px; + line-height: 1.5; + margin: 0; } + +.kuiPanelHeaderSection { + display: flex; + align-items: center; + flex: 1 1 auto; + margin-left: 25px; + margin-right: 25px; +} +.kuiPanelHeaderSection:not(:first-child):not(:last-child):not(:only-child) { + justify-content: center; } +.kuiPanelHeaderSection:first-child { + margin-left: 0; +} +.kuiPanelHeaderSection:last-child { + margin-right: 0; + flex: 0 1 auto; justify-content: flex-end; } +.kuiPanelHeaderSection:only-child { + margin-left: auto; } +.kuiPanelHeaderSection > * + * { + margin-left: 10px; } +.kuiPanelHeaderSection:only-child { + margin-left: 0; margin-right: auto; } + +.kuiPanelBody { + padding: 10px; +} + +.kuiEmptyTablePrompt { + display: flex; + flex-direction: column; + align-items: center; + padding: 30px; +} + +.kuiEmptyTablePrompt__message { + font-size: 20px; + color: #8D98A3; + line-height: 1.5; +} + +.kuiEmptyTablePrompt__actions { + margin-top: 10px; +} + +.kuiStatusText { + display: inline-flex; + align-items: baseline; +} + +.kuiStatusText--info { + color: #FFC0CB; +} + +.kuiStatusText--success { + color: #FFC0CB; +} + +.kuiStatusText--warning { + color: #FFCE7A; +} + +.kuiStatusText--error { + color: #FF6666; +} + +.kuiStatusText__icon { + margin-right: 6px; + width: 1.15em; max-height: 1.15em; } + +.kuiControlledTable { + background: #0A121A; +} +.kuiControlledTable .kuiTable { + border-top: none; } +.kuiControlledTable .kuiToolBarFooter { + border-top: none; } +.kuiControlledTable .kuiMenu--contained { + border-top: none; } + +.kuiTable { + width: 100%; + border: 1px solid #293847; + border-collapse: collapse; + background-color: #0A121A; +} + +.kuiTable--fluid { + width: auto; } +.kuiTable--fluid .kuiTableHeaderCell, +.kuiTable--fluid .kuiTableRowCell { + max-width: none; } + +.kuiTableHeaderCell { + font-size: 16px; + font-weight: 400; + text-align: left; + max-width: 20px; line-height: 1.5; + color: #8D98A3; +} + +.kuiTableHeaderCell__liner { + display: inline-block; + padding: 7px 8px 8px; +} + +.kuiTableHeaderCellButton { + user-select: none; cursor: pointer; + width: 100%; + appearance: none; background-color: transparent; border: 0; padding: 0; color: inherit; line-height: inherit; font-size: inherit; text-align: inherit; } +.kuiTableHeaderCellButton:hover .kuiTableSortIcon { + display: block; + opacity: 1; +} +.kuiTableHeaderCellButton .kuiTableHeaderCell__liner { + display: flex; + align-items: center; +} + +.kuiTableHeaderCell--alignRight { + text-align: right; +} + +.kuiTableSortIcon { + display: none; + pointer-events: none; + margin-left: 4px; +} +.kuiTableHeaderCellButton-isSorted .kuiTableSortIcon { + display: block; + opacity: 0.4; +} + +.kuiTableRow:hover .kuiTableRowHoverReveal { + display: inline-block; +} + +.kuiTableRowHoverReveal { + display: none; +} + +.kuiTableRowCell { + font-size: 16px; + font-weight: 400; + text-align: left; + max-width: 20px; color: #DFE5EF; + border-top: 1px solid #293847; + vertical-align: middle; +} + +.kuiTableRowCell__liner { + padding: 7px 8px 8px; line-height: 1.5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.kuiTableRowCell__liner > * { + vertical-align: middle; } + +.kuiTableRowCell--wrap .kuiTableRowCell__liner { + white-space: normal; +} + +.kuiTableRowCell--overflowingContent .kuiTableRowCell__liner { + overflow: visible; + white-space: normal; +} + +.kuiTableRowCell--expanded { + border-top-color: #0A121A; } + +.kuiTableRowCell--alignRight { + text-align: right; +} +.kuiTableRowCell--alignRight .kuiTableRowCell__liner { + text-align: right; +} + +.kuiTableHeaderCell--checkBox, +.kuiTableRowCell--checkBox { + width: 28px; line-height: 1; } +.kuiTableHeaderCell--checkBox .kuiTableRowCell__liner, +.kuiTableRowCell--checkBox .kuiTableRowCell__liner { + overflow: visible; } +.kuiTableHeaderCell--checkBox .kuiTableHeaderCell__liner, +.kuiTableHeaderCell--checkBox .kuiTableRowCell__liner, +.kuiTableRowCell--checkBox .kuiTableHeaderCell__liner, +.kuiTableRowCell--checkBox .kuiTableRowCell__liner { + padding-right: 0; +} + +.kuiTableInfo { + padding: 30px; + font-size: 20px; + color: #8D98A3; + line-height: 1.5; +} + +.kuiTabs { + display: flex; + border-bottom: 1px solid #293847; +} + +.kuiTab { + appearance: none; cursor: pointer; + padding: 10px 30px; + font-size: 16px; + color: #8D98A3; + background-color: transparent; border: 1px solid #293847; + border-radius: 0; margin-bottom: -1px; } +.kuiTab + .kuiTab { + border-left: none; +} +.kuiTab + .kuiTab:focus:not(.kuiTab-isSelected):not(:active) { + margin-left: -1px; } +.kuiTab:active { + outline: none !important; box-shadow: none; } +.kuiTab:focus { + outline: none; } +.kuiTab:focus:not(.kuiTab-isSelected):not(:active) { + z-index: 1; + color: #FFC0CB; + border: 1px solid #FFC0CB !important; +} +.kuiTab:hover:not(.kuiTab-isSelected) { + color: #ff8da1; + background-color: #101B25; +} +.kuiTab.kuiTab-isSelected { + cursor: default; + color: #DFE5EF; + background-color: transparent; + border-bottom-color: transparent; +} + +.kuiToolBar { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 30px; padding: 10px; + height: 50px; + background-color: transparent; + border: solid 1px #293847; +} +.kuiToolBar .kuiButton:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FFC0CB; } +a.kuiToolBar .kuiButton:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FFC0CB; } + +.kuiToolBar .kuiButton--danger:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FF6666; } +a.kuiToolBar .kuiButton--danger:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #293847, 0 0 0 2px #FF6666; } + +.kuiToolBar .kuiSelect { + border-color: #0e1721; +} +.kuiToolBar .kuiSelect:not(a):enabled:focus { + outline: none; + border-color: #FFC0CB; +} +a.kuiToolBar .kuiSelect:not(.kuiButton-isDisabled):focus { outline: none; + border-color: #FFC0CB; +} + +.kuiToolBarSection { + display: flex; + align-items: center; + flex: 1 1 auto; + margin-left: 25px; + margin-right: 25px; +} +.kuiToolBarSection:not(:first-child):not(:last-child):not(:only-child) { + justify-content: center; } +.kuiToolBarSection:first-child { + margin-left: 0; +} +.kuiToolBarSection:last-child { + margin-right: 0; + flex: 0 1 auto; justify-content: flex-end; } +.kuiToolBarSection:only-child { + margin-left: auto; } +.kuiToolBarSection > * + * { + margin-left: 10px; } + +.kuiToolBar--searchOnly .kuiToolBarSearch { + margin-left: 0 !important; } + +.kuiToolBarFooter { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 30px; padding: 10px; + height: 40px; + background-color: #0A121A; +} + +.kuiToolBarFooterSection { + display: flex; + align-items: center; + flex: 1 1 auto; + margin-left: 25px; + margin-right: 25px; +} +.kuiToolBarFooterSection:not(:first-child):not(:last-child):not(:only-child) { + justify-content: center; } +.kuiToolBarFooterSection:first-child { + margin-left: 0; +} +.kuiToolBarFooterSection:last-child { + margin-right: 0; + flex: 0 1 auto; justify-content: flex-end; } +.kuiToolBarFooterSection:only-child { + margin-left: auto; } +.kuiToolBarFooterSection > * + * { + margin-left: 10px; } + +.kuiToolBarSearch { + display: flex; + align-items: center; + margin-left: 25px; + margin-right: 25px; + flex: 1 1 auto; + max-width: 100%; line-height: 1.5; +} +.kuiToolBarSearch:first-child { + margin-left: 0; +} +.kuiToolBarSearch:last-child { + margin-right: 0; +} +.kuiToolBarSearch > * + * { + margin-left: 10px; } + +.kuiToolBarSearchBox { + flex: 1 1 auto; + position: relative; + font-size: 16px; + max-width: 800px; +} + +.kuiToolBarSearchBox__icon { + position: absolute; + top: 0.5em; + left: 0.7em; + font-size: 1em; + color: #acacac; +} + +.kuiToolBarSearchBox__input { + width: 100%; + min-width: 200px; + padding: 4px 12px 5px 28px; + font-family: var(--font-text); background-color: #0A121A; + color: #DFE5EF; + border-radius: 4px; + font-size: 1em; + border: 1px solid #293847; + line-height: normal; transition: border-color 0.1s linear; +} +.kuiToolBarSearchBox__input:focus { + outline: none; + border-color: #FFC0CB; +} + +.kuiToolBarText { + font-size: 16px; + line-height: 1.5; + color: #8D98A3; + white-space: nowrap; } + +.kuiTitle { + margin: 0; font-weight: 400; font-size: 24px; +} + +.kuiSubTitle { + margin: 0; font-weight: 400; font-size: 20px; +} + +.kuiTextTitle { + margin: 0; font-weight: 700; line-height: 1.5; + font-size: 16px; +} + +.kuiText { + margin: 0; font-weight: 400; line-height: 1.5; + font-size: 16px; +} + +.kuiSubText { + margin: 0; font-weight: 400; line-height: 1.5; + font-size: 14px; +} + +.kuiSubduedText { + color: #8D98A3 !important; +} + +.kuiVerticalRhythm + .kuiVerticalRhythm { + margin-top: 16px; +} + +.kuiVerticalRhythmSmall + .kuiVerticalRhythmSmall { + margin-top: 8px; +} + +.kuiVerticalRhythmLarge + .kuiVerticalRhythmLarge { + margin-top: 24px; +} + +.kuiVerticalRhythmXLarge + .kuiVerticalRhythmXLarge { + margin-top: 32px; +} + +.kuiView { + background-color: #fff; + flex: 1 1 auto; +} + +.kuiViewContent { + padding-top: 20px; + padding-bottom: 20px; + width: 100%; +} + +.kuiViewContent--constrainedWidth { + width: 100%; + max-width: 1100px; + margin-left: auto; + margin-right: auto; +} + +.kuiViewContentItem { + padding-left: 20px; + padding-right: 20px; +} diff --git a/packages/osd-ui-framework/dist/kui_v9_light.css b/packages/osd-ui-framework/dist/kui_v9_light.css new file mode 100644 index 000000000000..f7efab3e9de6 --- /dev/null +++ b/packages/osd-ui-framework/dist/kui_v9_light.css @@ -0,0 +1,1635 @@ +/*! + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +main { + display: block; } + +.kuiBar { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 30px; } + +.kuiBarSection { + display: flex; + align-items: center; + flex: 1 1 auto; + margin-left: 25px; + margin-right: 25px; +} +.kuiBarSection:not(:first-child):not(:last-child):not(:only-child) { + justify-content: center; } +.kuiBarSection:first-child { + margin-left: 0; +} +.kuiBarSection:last-child { + margin-right: 0; + flex: 0 1 auto; justify-content: flex-end; } +.kuiBarSection:only-child { + margin-left: auto; } +.kuiBarSection > * + * { + margin-left: 10px; } + +.kuiButton { + display: inline-block; appearance: none; + cursor: pointer; + padding: 4px 12px 5px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + height: 30px; + text-decoration: none; + border: none; + border-radius: 4px; +} +.kuiButton:disabled { + cursor: not-allowed; + opacity: 0.5; +} +a.kuiButton.kuiButton-isDisabled { + cursor: not-allowed; + opacity: 0.5; +} + +.kuiButton:enabled:active { + transform: translateY(1px); +} +a.kuiButton:not(.kuiButton-isDisabled):active { transform: translateY(1px); +} + +.kuiButton__inner { + display: flex; align-items: center; } + +.kuiButton--small { + font-size: 12px; + padding: 2px 8px 3px; + height: 22px; +} + +.kuiButton--fullWidth { + width: 100%; + text-align: center; +} + +.kuiButton--iconText .kuiButton__icon:first-child:not(:only-child) { + margin-right: 8px; +} +.kuiButton--iconText .kuiButton__icon:last-child:not(:only-child) { + margin-left: 8px; +} +.kuiButton--iconText.kuiButton--small .kuiButton__icon:first-child:not(:only-child) { + margin-right: 4px; +} +.kuiButton--iconText.kuiButton--small .kuiButton__icon:last-child:not(:only-child) { + margin-left: 4px; +} + +.kuiButton--basic { + color: #343741; + background-color: #F5F7FA; +} +.kuiButton--basic:not(a):enabled:focus { + color: #343741; +} +a.kuiButton--basic:not(.kuiButton-isDisabled):focus { color: #343741; +} + +.kuiButton--basic:enabled:hover { + background-color: #d3dce9 !important; } +a.kuiButton--basic:not(.kuiButton-isDisabled):hover { background-color: #d3dce9 !important; } + +.kuiButton--basic:enabled:active { + background-color: #d3dce9 !important; } +a.kuiButton--basic:not(.kuiButton-isDisabled):active { background-color: #d3dce9 !important; } + +.kuiButton--primary { + color: #FFF; + background-color: #006BB4; +} +.kuiButton--primary:not(a):enabled:focus { + color: #FFF; +} +a.kuiButton--primary:not(.kuiButton-isDisabled):focus { color: #FFF; +} + +.kuiButton--primary:enabled:hover { + color: #FFF !important; background-color: #004d81; +} +a.kuiButton--primary:not(.kuiButton-isDisabled):hover { color: #FFF !important; background-color: #004d81; +} + +.kuiButton--primary:enabled:active { + color: #FFF !important; background-color: #004d81; +} +a.kuiButton--primary:not(.kuiButton-isDisabled):active { color: #FFF !important; background-color: #004d81; +} + +.kuiButton--success { + color: #FFF; + background-color: #017D73; +} +.kuiButton--success:not(a):enabled:focus { + color: #FFF; +} +a.kuiButton--success:not(.kuiButton-isDisabled):focus { color: #FFF; +} + +.kuiButton--success:enabled:hover { + color: #FFF !important; background-color: #014a44; +} +a.kuiButton--success:not(.kuiButton-isDisabled):hover { color: #FFF !important; background-color: #014a44; +} + +.kuiButton--success:enabled:active { + color: #FFF !important; background-color: #014a44; +} +a.kuiButton--success:not(.kuiButton-isDisabled):active { color: #FFF !important; background-color: #014a44; +} + +.kuiButton--danger { + color: #BD271E; + border: solid 1px #BD271E; +} +.kuiButton--danger:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #FFF, 0 0 0 2px #BD271E; color: #BD271E; +} +a.kuiButton--danger:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #FFF, 0 0 0 2px #BD271E; color: #BD271E; +} + +.kuiButton--danger:enabled:hover { + color: #911e17 !important; + border: solid 1px #911e17; + background-color: rgba(189, 39, 30, 0.1); +} +a.kuiButton--danger:not(.kuiButton-isDisabled):hover { color: #911e17 !important; + border: solid 1px #911e17; + background-color: rgba(189, 39, 30, 0.1); +} + +.kuiButton--danger:enabled:active { + color: #911e17 !important; + border: solid 1px #911e17; + background-color: rgba(189, 39, 30, 0.1); +} +a.kuiButton--danger:not(.kuiButton-isDisabled):active { color: #911e17 !important; + border: solid 1px #911e17; + background-color: rgba(189, 39, 30, 0.1); +} + +.kuiButton--warning { + color: #FFF; + background-color: #F5A700; +} +.kuiButton--warning:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #FFF, 0 0 0 2px #F5A700; color: #FFF; +} +a.kuiButton--warning:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #FFF, 0 0 0 2px #F5A700; color: #FFF; +} + +.kuiButton--warning:enabled:hover { + color: #FFF !important; background-color: #c28400; +} +a.kuiButton--warning:not(.kuiButton-isDisabled):hover { color: #FFF !important; background-color: #c28400; +} + +.kuiButton--warning:enabled:active { + color: #FFF !important; background-color: #c28400; +} +a.kuiButton--warning:not(.kuiButton-isDisabled):active { color: #FFF !important; background-color: #c28400; +} + +.kuiButton--warning:disabled { + background-color: #ffbb29; +} +a.kuiButton--warning.kuiButton-isDisabled { + background-color: #ffbb29; +} + +.kuiButton--hollow { + color: #006BB4 !important; background-color: transparent; +} +.kuiButton--hollow:enabled:hover { + color: #004d81 !important; text-decoration: underline; +} +a.kuiButton--hollow:not(.kuiButton-isDisabled):hover { color: #004d81 !important; text-decoration: underline; +} + +.kuiButton--hollow:enabled:active { + color: #004d81 !important; text-decoration: underline; +} +a.kuiButton--hollow:not(.kuiButton-isDisabled):active { color: #004d81 !important; text-decoration: underline; +} + +.kuiButton--secondary { + color: #006BB4 !important; border: solid 1px #006BB4; +} +.kuiButton--secondary:enabled:hover { + color: #004d81 !important; border: solid 1px #004d81; + background-color: rgba(0, 107, 180, 0.1); + text-decoration: underline; +} +a.kuiButton--secondary:not(.kuiButton-isDisabled):hover { color: #004d81 !important; border: solid 1px #004d81; + background-color: rgba(0, 107, 180, 0.1); + text-decoration: underline; +} + +.kuiButton--secondary:enabled:active { + color: #004d81 !important; border: solid 1px #004d81; + background-color: rgba(0, 107, 180, 0.1); + text-decoration: underline; +} +a.kuiButton--secondary:not(.kuiButton-isDisabled):active { color: #004d81 !important; border: solid 1px #004d81; + background-color: rgba(0, 107, 180, 0.1); + text-decoration: underline; +} + +.kuiButtonGroup { + display: flex; + align-items: center; +} +.kuiButtonGroup .kuiButton + .kuiButton { + margin-left: 4px; +} + +.kuiButtonGroup--united > .kuiButton:not(:first-child):not(:last-child) { + border-radius: 0; +} +.kuiButtonGroup--united > .kuiButton:first-child { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.kuiButtonGroup--united > .kuiButton:last-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.kuiButtonGroup--united > .kuiButton:only-child { + border-radius: 4px 4px 4px 4px; +} +.kuiButtonGroup--united .kuiButton + .kuiButton { + margin-left: 0; +} + +.kuiButtonGroup--fullWidth { + display: flex; +} +.kuiButtonGroup--fullWidth > .kuiButton { + flex: 1 1 auto; + text-align: center; +} + +.eui-textCenter > .kuiButtonGroup, +.text-center > .kuiButtonGroup { + display: inline-block; +} + +.kuiCollapseButton { + appearance: none; + background-color: transparent; + padding: 4px; + border: none; + line-height: 1; + font-size: 16px; + color: #343741 !important; cursor: pointer; + opacity: 0.35; +} +.kuiCollapseButton:hover { + opacity: 1; +} + +.kuiAssistedInput { + display: inline-block; position: relative; +} + +.kuiAssistedInput__assistance { + position: absolute; + right: 12px; + top: 50%; transform: translateY(-50%); } + +.kuiCheckBox { + appearance: none; background-color: #fbfcfd; + border: 1px solid rgba(16, 38, 118, 0.1); + border-radius: 4px; + width: 16px; + height: 16px; + font: var(--font-text) !important; line-height: 1.5 !important; margin: 0 !important; font-family: var(--font-text) !important; font-size: 10px !important; transition: background-color 0.1s linear; +} +.kuiCheckBox::before { + position: relative; + left: 0.25em; + font-family: FontAwesome, sans-serif; + content: "\f00c"; + font-size: 1em; + opacity: 0; + color: #FFF; + transition: opacity 0.1s linear; +} +.kuiCheckBox:checked { + border-color: #006BB4; + background-color: #006BB4; +} +.kuiCheckBox:checked::before { + opacity: 1; +} +.kuiCheckBox:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #FFF, 0 0 0 2px #006BB4; } +.kuiCheckBox:disabled { + background-color: #eef2f7 !important; + border-color: #eef2f7 !important; + cursor: not-allowed !important; +} + +.kuiCheckBoxLabel { + display: flex; + align-items: center; + font-weight: normal !important; + line-height: 1.5; +} + +.kuiCheckBoxLabel__text { + font-size: 16px; + margin-left: 8px; +} + +.kuiLabel { + font-size: 16px; + line-height: 1.5; + font-weight: bold; + margin-bottom: 0; } + +.kuiSearchInput { + width: 180px; + display: inline-block; + position: relative; + font-size: 16px; + line-height: 1.5; +} +.kuiSearchInput.kuiSearchInput-isInvalid .kuiSearchInput__input { + border-color: #BD271E; +} + +.kuiSearchInput__icon { + position: absolute; + top: 0.5em; + left: 0.7em; + font-size: 1em; + color: #98A2B3; +} + +.kuiSearchInput__input { + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #343741; + background-color: #fbfcfd; + border: 1px solid rgba(16, 38, 118, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; padding-left: 28px; width: 100%; } +.kuiSearchInput__input:invalid { + border-color: #BD271E; +} +.kuiSearchInput__input:focus { + outline: none; + border-color: #006BB4; +} +.kuiSearchInput__input:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.kuiSearchInput--small { + width: 60px; +} + +.kuiSearchInput--large { + width: 400px; +} + +.kuiSelect { + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #343741; + background-color: #fbfcfd; + border: 1px solid rgba(16, 38, 118, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; padding-right: 30px; background-image: url('data:image/svg+xml;utf8,'); background-size: 14px; + background-repeat: no-repeat; + background-position: calc(100% - 8px); } +.kuiSelect:invalid { + border-color: #BD271E; +} +.kuiSelect:focus { + outline: none; + border-color: #006BB4; +} +.kuiSelect:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiSelect:-moz-focusring { + text-shadow: 0 0 0; } +.kuiSelect.kuiSelect-isInvalid { + border-color: #BD271E; +} +.kuiSelect:focus { + box-shadow: none; + outline: none; + border-color: #006BB4; +} + +.kuiSelect--small { + width: 60px; +} + +.kuiSelect--medium { + width: 180px; +} + +.kuiSelect--large { + width: 400px; +} + +.kuiStaticInput { + width: 180px; + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #343741; + border: 1px solid transparent; background-color: transparent; +} + +.kuiTextArea { + width: 180px; + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #343741; + background-color: #fbfcfd; + border: 1px solid rgba(16, 38, 118, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; } +.kuiTextArea:invalid { + border-color: #BD271E; +} +.kuiTextArea:focus { + outline: none; + border-color: #006BB4; +} +.kuiTextArea:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiTextArea:focus { + box-shadow: none; + outline: none; + border-color: #006BB4; +} +.kuiTextArea.kuiTextArea-isInvalid { + border-color: #BD271E; +} + +.kuiTextArea--nonResizable { + resize: none; +} + +.kuiTextArea--small { + width: 60px; +} + +.kuiTextArea--large { + width: 400px; +} + +.kuiTextInput { + width: 180px; + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #343741; + background-color: #fbfcfd; + border: 1px solid rgba(16, 38, 118, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; } +.kuiTextInput:invalid { + border-color: #BD271E; +} +.kuiTextInput:focus { + outline: none; + border-color: #006BB4; +} +.kuiTextInput:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiTextInput.kuiTextInput-isInvalid { + border-color: #BD271E; +} + +.kuiTextInput--small { + width: 60px; +} + +.kuiTextInput--large { + width: 400px; +} + +.kuiFieldGroup { + display: flex; + align-items: center; } + +.kuiFieldGroup--alignTop { + align-items: flex-start; +} + +.kuiFieldGroupSection { + line-height: 1.5; +} +.kuiFieldGroupSection + .kuiFieldGroupSection { + margin-left: 10px; +} + +.kuiFieldGroupSection--wide { + flex: 1 1 auto; +} +.kuiFieldGroupSection--wide > * { + width: 100%; +} + +.kuiIcon { + display: inline-block; font: normal normal normal 14px/1 FontAwesome, sans-serif; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } + +.kuiIcon--info { + color: #006BB4; +} + +.kuiIcon--success { + color: #017D73; +} + +.kuiIcon--warning { + color: #F5A700; +} + +.kuiIcon--error { + color: #BD271E; +} + +.kuiIcon--inactive { + color: #D3DAE6; +} + +.kuiIcon--basic { + color: #69707D; +} + +.kuiInfoPanel { + padding: 14px 20px 18px; + line-height: 1.5; + border: 2px solid; +} + +.kuiInfoPanel--info { + border-color: rgba(0, 107, 180, 0.25); } + +.kuiInfoPanel--success { + border-color: rgba(1, 125, 115, 0.25); } + +.kuiInfoPanel--warning { + border-color: rgba(245, 167, 0, 0.25); } + +.kuiInfoPanel--error { + border-color: rgba(189, 39, 30, 0.25); } + +.kuiInfoPanelHeader { + display: flex; + align-items: baseline; } + +.kuiInfoPanelHeader__icon { + margin-right: 10px; + font-size: 16px; + line-height: 1.5; +} + +.kuiInfoPanelHeader__title { + font-size: 16px; + line-height: 1.5; + font-weight: 700; +} + +.kuiInfoPanelBody { + margin-top: 8px; +} +.kuiInfoPanelBody > * + * { + margin-top: 8px; +} + +.kuiInfoPanelBody__message { + font-size: 16px; + line-height: 1.5; +} + +.kuiLink { + color: #006BB4; + text-decoration: none; + cursor: pointer; appearance: none; background-color: transparent; border: none; font-size: inherit; line-height: inherit; } +.kuiLink:visited, .kuiLink:active { + color: #006BB4; +} +.kuiLink:hover { + color: #004d81; + text-decoration: underline; +} + +.kuiLocalBreadcrumbs { + display: flex; + align-items: center; + padding: 12px 8px; border-bottom: 1px solid #D3DAE6; + flex-grow: 1; + flex-basis: 100%; + background-color: #FFF; +} + +.kuiLocalBreadcrumb { + font-size: 14px; + margin: 0; + font-weight: normal; +} +.kuiLocalBreadcrumb + .kuiLocalBreadcrumb { + margin-left: 6px; +} +.kuiLocalBreadcrumb + .kuiLocalBreadcrumb::before { + content: "/"; + user-select: none; + margin-right: 4px; + color: #D3DAE6; +} + +.kuiLocalBreadcrumb__link { + color: #006BB4; + text-decoration: none; + cursor: pointer; appearance: none; background-color: transparent; border: none; font-size: inherit; line-height: inherit; color: #006BB4; font-size: 16px; +} +.kuiLocalBreadcrumb__link:visited, .kuiLocalBreadcrumb__link:active { + color: #006BB4; +} +.kuiLocalBreadcrumb__link:hover { + color: #004d81; + text-decoration: underline; +} + +.kuiLocalBreadcrumb__emphasis { + font-weight: 700; +} + +.kuiDatePicker { + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; + line-height: 1.5; +} + +.kuiDatePickerNavigationCell { + padding: 0; +} + +.kuiDatePickerNavigation { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 4px; +} + +.kuiDatePickerNavigationButton { + appearance: none; + background-color: transparent; + border: none; + font-size: 14px; + color: #343741; + padding: 3px 6px; + border-radius: 4px; +} +.kuiDatePickerNavigationButton:hover, .kuiDatePickerNavigationButton:active { + cursor: pointer; + color: #F5F7FA; + background-color: #006BB4; +} +.kuiDatePickerNavigationButton:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px transparent, 0 0 0 2px #006BB4; color: #343741; } + +.kuiDatePickerHeaderCell { + padding: 9px 0; + color: #343741; + font-size: 14px; + font-weight: bold; + text-align: center; + line-height: 1.2; +} + +.kuiDatePickerRowCell { + padding: 0; + text-align: center; +} + +.kuiDatePickerRowCellContent { + appearance: none; + background-color: transparent; + width: 100%; + border: 1px solid transparent; + color: #343741; + font-size: 14px; + padding: 8px; + border-radius: 4px; + line-height: 1.2; +} +.kuiDatePickerRowCellContent:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px transparent, 0 0 0 2px #006BB4; color: #343741; } +.kuiDatePickerRowCellContent:disabled { + pointer-events: none; + opacity: 0.5; +} +.kuiDatePickerRowCellContent.kuiDatePickerRowCellContent-isOtherMonth { + visibility: hidden; + pointer-events: none; +} +.kuiDatePickerRowCellContent.kuiDatePickerRowCellContent-isCurrent { + color: #006BB4; +} +.kuiDatePickerRowCellContent.kuiDatePickerRowCellContent-isSelected { + background-color: #69707D; + color: #343741; +} +.kuiDatePickerRowCellContent:hover, .kuiDatePickerRowCellContent:active { + cursor: pointer; + color: #F5F7FA; + background-color: #006BB4; +} + +.kuiLocalDropdown { + position: relative; + padding: 10px 8px 14px; + background-color: transparent; + margin-bottom: 10px; + line-height: 20px; +} + +.kuiLocalDropdownCloseButton { + appearance: none; + background-color: transparent; + padding: 4px; + border: none; + line-height: 1; + font-size: 16px; + color: #343741 !important; cursor: pointer; + opacity: 0.35; + position: absolute; + top: 1px; + right: 5px; +} +.kuiLocalDropdownCloseButton:hover { + opacity: 1; +} + +.kuiLocalDropdownPanels { + display: flex; +} + +.kuiLocalDropdownPanel { + flex: 1 1 0%; +} + +.kuiLocalDropdownPanel--left { + margin-right: 30px; +} + +.kuiLocalDropdownPanel--right { + margin-left: 30px; +} + +.kuiLocalDropdownTitle { + margin-top: 0; margin-bottom: 12px; + font-size: 18px; + color: #343741; +} + +.kuiLocalDropdownSection { + margin-bottom: 16px; +} +.kuiLocalDropdownSection:last-child { + margin-bottom: 0; +} + +.kuiLocalDropdownHeader { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 6px; +} + +.kuiLocalDropdownHeader__label { + font-size: 14px; + font-weight: 700; + margin-bottom: 0; color: #343741; +} + +.kuiLocalDropdownHeader__actions { + display: flex; +} + +.kuiLocalDropdownHeader__action { + color: #006BB4; + font-size: 12px; + text-decoration: none; + cursor: pointer; +} +.kuiLocalDropdownHeader__action + .kuiLocalDropdownHeader__action { + margin-left: 10px; +} +.kuiLocalDropdownHeader__action:hover, .kuiLocalDropdownHeader__action:active { + color: #004d81; +} + +.kuiLocalDropdownInput { + display: block; + width: 100%; + margin-bottom: 12px; + padding: 5px 15px; + font-size: 14px; + color: #343741; + background-color: #fbfcfd; + border: 1px solid rgba(16, 38, 118, 0.1); + border-radius: 4px; +} +.kuiLocalDropdownInput:focus { + border-color: #006BB4; +} + +.kuiLocalDropdownFormNote { + font-size: 14px; + color: #69707D; +} + +.kuiLocalDropdownWarning { + margin-bottom: 16px; + padding: 6px 10px; + font-size: 14px; + color: #343741; + background-color: #FFF; + border-left: solid 2px #BD271E; +} + +.kuiLocalDropdownHelpText { + margin-bottom: 16px; + font-size: 14px; + color: #69707D; +} + +.kuiLocalMenu { + display: flex; + align-items: stretch; + padding-top: 8px; + padding-bottom: 8px; +} + +.kuiLocalMenuItem { + display: flex; + align-items: center; + padding: 2px 8px; + font-size: 16px; + background-color: transparent; + color: #343741; + border: 0; + cursor: pointer; + border-bottom: solid 2px transparent; +} +.kuiLocalMenuItem:hover, .kuiLocalMenuItem:focus { + background-color: rgba(0, 107, 180, 0.15); + text-decoration: underline; +} +.kuiLocalMenuItem.kuiLocalMenuItem-isSelected { + color: #006BB4; + background-color: transparent; + border-color: #006BB4; + z-index: 2; +} +.kuiLocalMenuItem.kuiLocalMenuItem-isSelected:hover, .kuiLocalMenuItem.kuiLocalMenuItem-isSelected:focus { + text-decoration: none; +} +.kuiLocalMenuItem.kuiLocalMenuItem-isDisabled { + opacity: 0.5; + cursor: not-allowed; +} +.kuiLocalMenuItem.kuiLocalMenuItem-isDisabled:hover { + background-color: transparent; + text-decoration: none; +} + +.kuiLocalMenuItem__icon { + margin-right: 5px; + margin-bottom: -1px; +} + +.kuiLocalNav { + display: flex; + flex-direction: column; + justify-content: space-between; + min-height: 69px; color: #343741; + background-color: #FFF; + line-height: 1.5; + border-bottom: solid 1px #D3DAE6; +} + +.kuiLocalNavRow { + display: flex; + align-items: stretch; + justify-content: space-between; +} + +.kuiLocalNavRow__section { + display: flex; + align-items: stretch; +} + +.kuiLocalNavRow--secondary { + padding: 0 8px; align-items: flex-start; } + +.kuiLocalSearch { + display: flex; + width: 100%; + margin-bottom: 8px; +} + +.kuiLocalSearchInput { + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #343741; + background-color: #fbfcfd; + border: 1px solid rgba(16, 38, 118, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; flex: 1 1 100%; + border-color: #FFF; + border-color: #D3DAE6; + border-radius: 4px 0 0 4px; +} +.kuiLocalSearchInput:invalid { + border-color: #BD271E; +} +.kuiLocalSearchInput:focus { + outline: none; + border-color: #006BB4; +} +.kuiLocalSearchInput:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiLocalSearchInput:focus { + box-shadow: none; +} +.kuiLocalSearchInput.kuiLocalSearchInput-isInvalid { + border-color: #BD271E; +} + +.kuiLocalSearchInput--secondary { + height: 32px; + flex: 0 0 auto; + border-radius: 0; + border-left-width: 0; +} + +.kuiLocalSearchInput, +.kuiLocalSearchAssistedInput__input { + padding-right: 6em; } + +.kuiLocalSearchAssistedInput__assistance { + position: absolute; + right: 6px; + top: 50%; z-index: 2; + transform: translateY(-50%); } + +.kuiLocalSearchSelect { + appearance: none; + font-family: var(--font-text); + padding: 4px 12px 4px; + font-size: 16px; + font-weight: 400; + line-height: 1.5; + color: #343741; + background-color: #fbfcfd; + border: 1px solid rgba(16, 38, 118, 0.1); + border-radius: 4px; + transition: border-color 0.1s linear; + min-height: 32px; padding-right: 30px; background-image: url('data:image/svg+xml;utf8,'); background-size: 14px; + background-repeat: no-repeat; + background-position: calc(100% - 8px); border-left-width: 0; + border-radius: 0; +} +.kuiLocalSearchSelect:invalid { + border-color: #BD271E; +} +.kuiLocalSearchSelect:focus { + outline: none; + border-color: #006BB4; +} +.kuiLocalSearchSelect:disabled { + opacity: 0.4; + cursor: not-allowed; +} +.kuiLocalSearchSelect:-moz-focusring { + text-shadow: 0 0 0; } + +.kuiLocalSearchButton { + width: 43px; + height: 32px; + font-size: 16px; + line-height: 0; color: #FFF; + background-color: #006BB4; + border: 0; + border-radius: 0 4px 4px 0; +} +.kuiLocalSearchButton:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #006BB4; } + +.kuiLocalTabs { + display: flex; + align-items: flex-end; + height: 100%; +} + +.kuiLocalTab { + padding: 5px 0 6px; + font-size: 18px; + color: #343741; + border-bottom: 2px solid transparent; + text-decoration: none; + cursor: pointer; + margin-top: 0 !important; margin-bottom: 0 !important; } +.kuiLocalTab:hover:not(.kuiLocalTab-isDisabled), .kuiLocalTab:active:not(.kuiLocalTab-isDisabled) { + color: #006BB4; +} +.kuiLocalTab.kuiLocalTab-isSelected { + color: #006BB4; + border-bottom-color: #006BB4; + cursor: default; +} +.kuiLocalTab.kuiLocalTab-isDisabled { + opacity: 0.5; + cursor: default; } +.kuiLocalTab + .kuiLocalTab { + margin-left: 15px; +} + +.kuiLocalTitle { + display: flex; + align-items: center; + padding: 12px 8px; + font-size: 16px; + font-weight: bold; + border-bottom: 1px solid #D3DAE6; + flex-grow: 1; + flex-basis: 100%; + background-color: #FFF; +} +.kuiLocalTitle:empty { + padding: 0; + display: none; +} + +.kuiPager { + display: flex; + align-items: center; +} +.kuiPager > * + * { + margin-left: 10px; } + +.kuiPagerText { + font-size: 16px; + line-height: 1.5; + color: #69707D; + white-space: nowrap; } + +.kuiPanel { + box-shadow: 0 2px 2px -1px rgba(152, 162, 179, 0.3), 0 1px 5px -2px rgba(152, 162, 179, 0.3); + background-color: #FFF; + border: 1px solid #D3DAE6; + border-radius: 4px; +} + +.kuiPanel--prompt { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + justify-content: center; + min-height: 300px; +} +.kuiPanel--prompt .kuiPanelBody { + padding: 30px; + max-width: 500px; +} + +.kuiPanel--noBorder { + border: none; +} + +.kuiPanel--withToolBar { + border-top: none; + border-radius: 0; +} + +.kuiPanel--centered { + display: flex; + justify-content: center; + align-items: center; +} + +.kuiPanelHeader { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 30px; padding: 10px; + height: 50px; + border-bottom: 1px solid #D3DAE6; +} +.kuiPanelHeader .kuiButton:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #006BB4; } +a.kuiPanelHeader .kuiButton:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #006BB4; } + +.kuiPanelHeader .kuiButton--danger:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #BD271E; } +a.kuiPanelHeader .kuiButton--danger:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #BD271E; } + +.kuiPanelHeader .kuiSelect { + border-color: #fbfcfd; +} +.kuiPanelHeader .kuiSelect:not(a):enabled:focus { + outline: none; + border-color: #006BB4; +} +a.kuiPanelHeader .kuiSelect:not(.kuiButton-isDisabled):focus { outline: none; + border-color: #006BB4; +} + +.kuiPanelHeader__title { + font-size: 20px; + line-height: 1.5; + margin: 0; } + +.kuiPanelHeaderSection { + display: flex; + align-items: center; + flex: 1 1 auto; + margin-left: 25px; + margin-right: 25px; +} +.kuiPanelHeaderSection:not(:first-child):not(:last-child):not(:only-child) { + justify-content: center; } +.kuiPanelHeaderSection:first-child { + margin-left: 0; +} +.kuiPanelHeaderSection:last-child { + margin-right: 0; + flex: 0 1 auto; justify-content: flex-end; } +.kuiPanelHeaderSection:only-child { + margin-left: auto; } +.kuiPanelHeaderSection > * + * { + margin-left: 10px; } +.kuiPanelHeaderSection:only-child { + margin-left: 0; margin-right: auto; } + +.kuiPanelBody { + padding: 10px; +} + +.kuiEmptyTablePrompt { + display: flex; + flex-direction: column; + align-items: center; + padding: 30px; +} + +.kuiEmptyTablePrompt__message { + font-size: 20px; + color: #69707D; + line-height: 1.5; +} + +.kuiEmptyTablePrompt__actions { + margin-top: 10px; +} + +.kuiStatusText { + display: inline-flex; + align-items: baseline; +} + +.kuiStatusText--info { + color: #006BB4; +} + +.kuiStatusText--success { + color: #017D73; +} + +.kuiStatusText--warning { + color: #F5A700; +} + +.kuiStatusText--error { + color: #BD271E; +} + +.kuiStatusText__icon { + margin-right: 6px; + width: 1.15em; max-height: 1.15em; } + +.kuiControlledTable { + background: #FFF; +} +.kuiControlledTable .kuiTable { + border-top: none; } +.kuiControlledTable .kuiToolBarFooter { + border-top: none; } +.kuiControlledTable .kuiMenu--contained { + border-top: none; } + +.kuiTable { + width: 100%; + border: 1px solid #D3DAE6; + border-collapse: collapse; + background-color: #FFF; +} + +.kuiTable--fluid { + width: auto; } +.kuiTable--fluid .kuiTableHeaderCell, +.kuiTable--fluid .kuiTableRowCell { + max-width: none; } + +.kuiTableHeaderCell { + font-size: 16px; + font-weight: 400; + text-align: left; + max-width: 20px; line-height: 1.5; + color: #69707D; +} + +.kuiTableHeaderCell__liner { + display: inline-block; + padding: 7px 8px 8px; +} + +.kuiTableHeaderCellButton { + user-select: none; cursor: pointer; + width: 100%; + appearance: none; background-color: transparent; border: 0; padding: 0; color: inherit; line-height: inherit; font-size: inherit; text-align: inherit; } +.kuiTableHeaderCellButton:hover .kuiTableSortIcon { + display: block; + opacity: 1; +} +.kuiTableHeaderCellButton .kuiTableHeaderCell__liner { + display: flex; + align-items: center; +} + +.kuiTableHeaderCell--alignRight { + text-align: right; +} + +.kuiTableSortIcon { + display: none; + pointer-events: none; + margin-left: 4px; +} +.kuiTableHeaderCellButton-isSorted .kuiTableSortIcon { + display: block; + opacity: 0.4; +} + +.kuiTableRow:hover .kuiTableRowHoverReveal { + display: inline-block; +} + +.kuiTableRowHoverReveal { + display: none; +} + +.kuiTableRowCell { + font-size: 16px; + font-weight: 400; + text-align: left; + max-width: 20px; color: #343741; + border-top: 1px solid #D3DAE6; + vertical-align: middle; +} + +.kuiTableRowCell__liner { + padding: 7px 8px 8px; line-height: 1.5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.kuiTableRowCell__liner > * { + vertical-align: middle; } + +.kuiTableRowCell--wrap .kuiTableRowCell__liner { + white-space: normal; +} + +.kuiTableRowCell--overflowingContent .kuiTableRowCell__liner { + overflow: visible; + white-space: normal; +} + +.kuiTableRowCell--expanded { + border-top-color: #FFF; } + +.kuiTableRowCell--alignRight { + text-align: right; +} +.kuiTableRowCell--alignRight .kuiTableRowCell__liner { + text-align: right; +} + +.kuiTableHeaderCell--checkBox, +.kuiTableRowCell--checkBox { + width: 28px; line-height: 1; } +.kuiTableHeaderCell--checkBox .kuiTableRowCell__liner, +.kuiTableRowCell--checkBox .kuiTableRowCell__liner { + overflow: visible; } +.kuiTableHeaderCell--checkBox .kuiTableHeaderCell__liner, +.kuiTableHeaderCell--checkBox .kuiTableRowCell__liner, +.kuiTableRowCell--checkBox .kuiTableHeaderCell__liner, +.kuiTableRowCell--checkBox .kuiTableRowCell__liner { + padding-right: 0; +} + +.kuiTableInfo { + padding: 30px; + font-size: 20px; + color: #69707D; + line-height: 1.5; +} + +.kuiTabs { + display: flex; + border-bottom: 1px solid #D3DAE6; +} + +.kuiTab { + appearance: none; cursor: pointer; + padding: 10px 30px; + font-size: 16px; + color: #69707D; + background-color: transparent; border: 1px solid #D3DAE6; + border-radius: 0; margin-bottom: -1px; } +.kuiTab + .kuiTab { + border-left: none; +} +.kuiTab + .kuiTab:focus:not(.kuiTab-isSelected):not(:active) { + margin-left: -1px; } +.kuiTab:active { + outline: none !important; box-shadow: none; } +.kuiTab:focus { + outline: none; } +.kuiTab:focus:not(.kuiTab-isSelected):not(:active) { + z-index: 1; + color: #006BB4; + border: 1px solid #006BB4 !important; +} +.kuiTab:hover:not(.kuiTab-isSelected) { + color: #004d81; + background-color: #F5F7FA; +} +.kuiTab.kuiTab-isSelected { + cursor: default; + color: #343741; + background-color: transparent; + border-bottom-color: transparent; +} + +.kuiToolBar { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 30px; padding: 10px; + height: 50px; + background-color: transparent; + border: solid 1px #D3DAE6; +} +.kuiToolBar .kuiButton:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #006BB4; } +a.kuiToolBar .kuiButton:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #006BB4; } + +.kuiToolBar .kuiButton--danger:not(a):enabled:focus { + z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #BD271E; } +a.kuiToolBar .kuiButton--danger:not(.kuiButton-isDisabled):focus { z-index: 1; outline: none !important; box-shadow: 0 0 0 1px #D3DAE6, 0 0 0 2px #BD271E; } + +.kuiToolBar .kuiSelect { + border-color: #fbfcfd; +} +.kuiToolBar .kuiSelect:not(a):enabled:focus { + outline: none; + border-color: #006BB4; +} +a.kuiToolBar .kuiSelect:not(.kuiButton-isDisabled):focus { outline: none; + border-color: #006BB4; +} + +.kuiToolBarSection { + display: flex; + align-items: center; + flex: 1 1 auto; + margin-left: 25px; + margin-right: 25px; +} +.kuiToolBarSection:not(:first-child):not(:last-child):not(:only-child) { + justify-content: center; } +.kuiToolBarSection:first-child { + margin-left: 0; +} +.kuiToolBarSection:last-child { + margin-right: 0; + flex: 0 1 auto; justify-content: flex-end; } +.kuiToolBarSection:only-child { + margin-left: auto; } +.kuiToolBarSection > * + * { + margin-left: 10px; } + +.kuiToolBar--searchOnly .kuiToolBarSearch { + margin-left: 0 !important; } + +.kuiToolBarFooter { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 30px; padding: 10px; + height: 40px; + background-color: #FFF; +} + +.kuiToolBarFooterSection { + display: flex; + align-items: center; + flex: 1 1 auto; + margin-left: 25px; + margin-right: 25px; +} +.kuiToolBarFooterSection:not(:first-child):not(:last-child):not(:only-child) { + justify-content: center; } +.kuiToolBarFooterSection:first-child { + margin-left: 0; +} +.kuiToolBarFooterSection:last-child { + margin-right: 0; + flex: 0 1 auto; justify-content: flex-end; } +.kuiToolBarFooterSection:only-child { + margin-left: auto; } +.kuiToolBarFooterSection > * + * { + margin-left: 10px; } + +.kuiToolBarSearch { + display: flex; + align-items: center; + margin-left: 25px; + margin-right: 25px; + flex: 1 1 auto; + max-width: 100%; line-height: 1.5; +} +.kuiToolBarSearch:first-child { + margin-left: 0; +} +.kuiToolBarSearch:last-child { + margin-right: 0; +} +.kuiToolBarSearch > * + * { + margin-left: 10px; } + +.kuiToolBarSearchBox { + flex: 1 1 auto; + position: relative; + font-size: 16px; + max-width: 800px; +} + +.kuiToolBarSearchBox__icon { + position: absolute; + top: 0.5em; + left: 0.7em; + font-size: 1em; + color: #acacac; +} + +.kuiToolBarSearchBox__input { + width: 100%; + min-width: 200px; + padding: 4px 12px 5px 28px; + font-family: var(--font-text); background-color: #FFF; + color: #343741; + border-radius: 4px; + font-size: 1em; + border: 1px solid #D3DAE6; + line-height: normal; transition: border-color 0.1s linear; +} +.kuiToolBarSearchBox__input:focus { + outline: none; + border-color: #006BB4; +} + +.kuiToolBarText { + font-size: 16px; + line-height: 1.5; + color: #69707D; + white-space: nowrap; } + +.kuiTitle { + margin: 0; font-weight: 400; font-size: 24px; +} + +.kuiSubTitle { + margin: 0; font-weight: 400; font-size: 20px; +} + +.kuiTextTitle { + margin: 0; font-weight: 700; line-height: 1.5; + font-size: 16px; +} + +.kuiText { + margin: 0; font-weight: 400; line-height: 1.5; + font-size: 16px; +} + +.kuiSubText { + margin: 0; font-weight: 400; line-height: 1.5; + font-size: 14px; +} + +.kuiSubduedText { + color: #69707D !important; +} + +.kuiVerticalRhythm + .kuiVerticalRhythm { + margin-top: 16px; +} + +.kuiVerticalRhythmSmall + .kuiVerticalRhythmSmall { + margin-top: 8px; +} + +.kuiVerticalRhythmLarge + .kuiVerticalRhythmLarge { + margin-top: 24px; +} + +.kuiVerticalRhythmXLarge + .kuiVerticalRhythmXLarge { + margin-top: 32px; +} + +.kuiView { + background-color: #fff; + flex: 1 1 auto; +} + +.kuiViewContent { + padding-top: 20px; + padding-bottom: 20px; + width: 100%; +} + +.kuiViewContent--constrainedWidth { + width: 100%; + max-width: 1100px; + margin-left: auto; + margin-right: auto; +} + +.kuiViewContentItem { + padding-left: 20px; + padding-right: 20px; +} diff --git a/packages/osd-ui-framework/src/kui_v9_dark.scss b/packages/osd-ui-framework/src/kui_v9_dark.scss new file mode 100644 index 000000000000..fe1338cf9b69 --- /dev/null +++ b/packages/osd-ui-framework/src/kui_v9_dark.scss @@ -0,0 +1,15 @@ +// EUI global scope is used for KUI variables till fully deprecated +@import "../../../node_modules/@elastic/eui/src/themes/v9/v9_colors_dark"; +@import "../../../node_modules/@elastic/eui/src/global_styling/functions/index"; +@import "../../../node_modules/@elastic/eui/src/global_styling/variables/index"; +@import "../../../node_modules/@elastic/eui/src/global_styling/mixins/index"; + +// Configuration +@import "global_styling/variables/index"; + +// Coreß +@import "global_styling/mixins/index"; +@import "global_styling/reset/index"; + +// Components +@import "components/index"; diff --git a/packages/osd-ui-framework/src/kui_v9_light.scss b/packages/osd-ui-framework/src/kui_v9_light.scss new file mode 100644 index 000000000000..535be1bf1bfd --- /dev/null +++ b/packages/osd-ui-framework/src/kui_v9_light.scss @@ -0,0 +1,15 @@ +// EUI global scope is used for KUI variables till fully deprecated +@import "../../../node_modules/@elastic/eui/src/themes/v9/v9_colors_light"; +@import "../../../node_modules/@elastic/eui/src/global_styling/functions/index"; +@import "../../../node_modules/@elastic/eui/src/global_styling/variables/index"; +@import "../../../node_modules/@elastic/eui/src/global_styling/mixins/index"; + +// Configuration +@import "global_styling/variables/index"; + +// Core +@import "global_styling/mixins/index"; +@import "global_styling/reset/index"; + +// Components +@import "components/index"; diff --git a/packages/osd-ui-shared-deps/theme.test.ts b/packages/osd-ui-shared-deps/theme.test.ts new file mode 100644 index 000000000000..1786f53af58c --- /dev/null +++ b/packages/osd-ui-shared-deps/theme.test.ts @@ -0,0 +1,17 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +describe('@osd/ui-shared-deps/theme', () => { + it('should return variables for each theme', async () => { + const oldTag = global.__osdThemeTag__; + for (const v of ['v7', 'v8', 'v9']) { + global.__osdThemeTag__ = `${v}light`; + const { euiThemeVars } = await import('./theme'); + expect(euiThemeVars).toBeTruthy(); + jest.resetModules(); + } + global.__osdThemeTag__ = oldTag; + }); +}); diff --git a/packages/osd-ui-shared-deps/theme.ts b/packages/osd-ui-shared-deps/theme.ts index 082f468175e2..cf769ab3f94a 100644 --- a/packages/osd-ui-shared-deps/theme.ts +++ b/packages/osd-ui-shared-deps/theme.ts @@ -47,6 +47,9 @@ export let euiDarkVars: Theme; if (themeVersion === 'v7') { euiLightVars = require('@elastic/eui/dist/eui_theme_light.json'); euiDarkVars = require('@elastic/eui/dist/eui_theme_dark.json'); +} else if (themeVersion === 'v9') { + euiLightVars = require('@elastic/eui/dist/eui_theme_v9_light.json'); + euiDarkVars = require('@elastic/eui/dist/eui_theme_v9_dark.json'); } else { euiLightVars = require('@elastic/eui/dist/eui_theme_next_light.json'); euiDarkVars = require('@elastic/eui/dist/eui_theme_next_dark.json'); diff --git a/packages/osd-ui-shared-deps/theme_config.d.ts b/packages/osd-ui-shared-deps/theme_config.d.ts index 0ca80280434f..ff88a4965aca 100644 --- a/packages/osd-ui-shared-deps/theme_config.d.ts +++ b/packages/osd-ui-shared-deps/theme_config.d.ts @@ -7,7 +7,7 @@ * Types for valid theme tags (themeVersion + themeMode) * Note: used by @osd/optimizer */ -export type ThemeTag = 'v7light' | 'v7dark' | 'v8light' | 'v8dark'; +export type ThemeTag = 'v7light' | 'v7dark' | 'v8light' | 'v8dark' | 'v9light' | 'v9dark'; export type ThemeTags = readonly ThemeTag[]; /** diff --git a/packages/osd-ui-shared-deps/theme_config.js b/packages/osd-ui-shared-deps/theme_config.js index f128925bbbcb..0ccd422e321d 100644 --- a/packages/osd-ui-shared-deps/theme_config.js +++ b/packages/osd-ui-shared-deps/theme_config.js @@ -14,6 +14,7 @@ const THEME_MODES = ['light', 'dark']; const THEME_VERSION_LABEL_MAP = { v7: 'v7', v8: 'Next (preview)', + v9: 'v9 (preview)', }; const THEME_VERSION_VALUE_MAP = { // allow version lookup by label ... @@ -41,4 +42,5 @@ exports.themeCssDistFilenames = THEME_VERSIONS.reduce((map, v) => { exports.kuiCssDistFilenames = { v7: { dark: 'kui_dark.css', light: 'kui_light.css' }, v8: { dark: 'kui_next_dark.css', light: 'kui_next_light.css' }, + v9: { dark: 'kui_v9_dark.css', light: 'kui_v9_light.css' }, }; diff --git a/packages/osd-ui-shared-deps/webpack.config.js b/packages/osd-ui-shared-deps/webpack.config.js index d9bfd81af523..8a9e50dd05ef 100644 --- a/packages/osd-ui-shared-deps/webpack.config.js +++ b/packages/osd-ui-shared-deps/webpack.config.js @@ -47,6 +47,8 @@ exports.getWebpackConfig = ({ dev = false } = {}) => ({ 'osd-ui-shared-deps.v7.light': ['@elastic/eui/dist/eui_theme_light.css'], 'osd-ui-shared-deps.v8.dark': ['@elastic/eui/dist/eui_theme_next_dark.css'], 'osd-ui-shared-deps.v8.light': ['@elastic/eui/dist/eui_theme_next_light.css'], + 'osd-ui-shared-deps.v9.dark': ['@elastic/eui/dist/eui_theme_v9_dark.css'], + 'osd-ui-shared-deps.v9.light': ['@elastic/eui/dist/eui_theme_v9_light.css'], }, context: __dirname, devtool: dev ? '#cheap-source-map' : false, diff --git a/src/core/public/core_app/styles/_globals_v9dark.scss b/src/core/public/core_app/styles/_globals_v9dark.scss new file mode 100644 index 000000000000..ba3a02ca3922 --- /dev/null +++ b/src/core/public/core_app/styles/_globals_v9dark.scss @@ -0,0 +1,7 @@ +// v8dark global scope +// --- +// prepended to all .scss imports (from JS, when v8dark theme selected) + +@import "@elastic/eui/src/themes/v9/v9_colors_dark"; +@import "@elastic/eui/src/themes/v9/v9_globals"; +@import "./mixins"; diff --git a/src/core/public/core_app/styles/_globals_v9light.scss b/src/core/public/core_app/styles/_globals_v9light.scss new file mode 100644 index 000000000000..74c238b5378d --- /dev/null +++ b/src/core/public/core_app/styles/_globals_v9light.scss @@ -0,0 +1,7 @@ +// v8light global scope +// --- +// prepended to all .scss imports (from JS, when v8light theme selected) + +@import "@elastic/eui/src/themes/v9/v9_colors_light"; +@import "@elastic/eui/src/themes/v9/v9_globals"; +@import "./mixins"; diff --git a/src/core/server/core_app/assets/fonts/fira_code/FiraCode-VariableFont_wght.ttf b/src/core/server/core_app/assets/fonts/fira_code/FiraCode-VariableFont_wght.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5655ed51458712ec48319bb13356fa691a9d0334 GIT binary patch literal 259308 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
e%L*2#&7!4HF7%D4x5E%Y;v z`-p!#?%{`5JPwxDd$RrEM*o|woABV#FLk{~Yrr|Ob(W4R**YtamDW&stjJJ0R^+tu zSZNKF$4YCcJXT~V9V>DP@>r3fbgalwd927#I#y(;JXT~V9V-l~j1?J5$BGP<#|ne8 zu_Bisj};a(2#=zi7Mg;pj*S)uXR|0x4Xp})@BJ2D?KW?XRD@O)e80D#W}Cc5szR%R z-ru@j(_2vYK5s$gHgAp8hF0a+_N|fX(5m2wX2^4&rUN7ZtsvX5fu~Bd^JWh^K?o?7n@(sdq zmFj{jgi5eY_=9}|n0akrHKuwA_3dLH7D8EY$Ugfu!kSw8C``6&X&pIwsRRFU@|p?K zEK=`PniZ(uSubrQweweBNN#*O6=&(4ns{*8gfUg4VjD9=Z}{G4m(TVPzqa+w8&~lkY?) z+i-*C@cTqt3pbil)Wb)Gr1-fbeE!Q%C8<2jJa+_wb>$#(y-x zoo=?^ZowK@CtZ^2NF523!s__II(A3cJ~15u^M}Q0LS0iG{h$qCOB#pCtk#I>XS<0B z_T*XV=oY8PrFyGc;!Czz*XBvx7LuF%F6j{|Nu6OxB7c!HclXW^mNiw={#k-Q*nI?x zdN=5eebGPEo$QQb{Gc@UV7Elm4nv?nykk6QC5&78%N9QZBwyY3L!IGl9T$+kV@lS9 zyuF!!)z$GA_MD$UZ$C&mvxnj;y;IeIOA&llkZWQjtxvgA0~FD!`l*JXK1zT3p;jOG z7GcJ8?r++-W4>LC#GxbB;FGVf$xmN2x!;aK1v_VM{kXL3`o8^Nlr1{;;)_R5ojreC zkeYIY?M*pc%*I>K1z3-(&kmije(W*g|K2-f)U#|KnLY85-oQ=2H>CFnJXC5%hZUd$ z-FIsPIyeI}993@p0BUgQOUV;{)h|JMTaoE7aeSddRHlRz>V8BTh~T zjQ9_)lWfTMR)$057b%q+AlcOsY||@gYN#p}<~FSqDuFePp?m~9O?TANUNpNS*$yFO zHjdamA#Z+y_g2RxfBeN4AAfZH`bUfR42Uinle#!+>Mk#&IOKiAMV}x((`(< zhHMbkVBpKbflHHbH+7jY16IF!EJ@v(9 zOW!PskB$!sK6dw*hRunaecW3eetc%Z(}k7ii{~878(Q(Hx@@59WCzFH(pMMs zlHr$^k5@1CYb;qjzc}@U_1ixxNjqlP^(~1$Npbn0`FH*s#z(Nv%LkyIEyvYECAd_( zzwkwI9{9Tv`1S?94v25|MJBj$Ta+{Eb7Apubc>K9omN~CIVt-(3AMNz`+Hhv zW7*S=7S|sQ7`CZmN<*TnYr-PKKRM+wuJ#FaQ|7PU#`j9j^y}w4b9!0*Vzg#`^XL38 z>S8%ogW`yID6A(3jPTLRWR(%q+tT<0*)z+HgfBMkkaX+0zHi_pWFdTU_Qs8C7MAUe z@PB%C<%yiii|XQK;_<7}_h)N;bNqMw^<3Ji_fwBP{>0WrCCk$098{^cwTEHf!! z&tmynO9467%?BA(~#!nv;a}RlNMY>%}<-vQT z!#ru|*b(~JSpA5xz@QBMG*YO7-%*yK%AM^-k2s1{@d~1T<~-pRl}vu;@Ts?x(%yaQ^ji~#4lyJL zThz-=6o728i1V{HYp%7jyHAk;u3Yl+YYR~SifeTXt}XVBit-&16%{af&$MZKCbPdn z)gnncPf=J*gmV-HDJa@!#F#N7e45L!Q zL^c`>LRQm<{EoNMBtz%ILh#H}=)4=CngcjnmWq5^sTf#$Hpe=o;rruUZ8yWsQ@^f> zwA)lUd24L)gcpUX)E(1&@=6;H6jqkZJGCe`-Mg?ZI&DmL9vxq6oBQzZpmaB5>2#uP zBUNOnXeNaR*B(mRn4i3GOz|7b%Px#f3R#o7ZO@*@solb6?{Anlc|l}Y{1KrlV^dP) z&K{lO)=aN_wjeG!E;?lYl9dZe>*r=y`i4#%Lt{7^nmvRd)ZbPb_M0v>@E(R}?s{2w zp~}NBD<_RK7=9;ZWGC=`1$c|Xl!ugt@7ap)`xZpbI+j`T+TwXnkB=L*CU@oDv2}3~ zY2Ky6lo?V)-(K0zEnfIaaa?rL=-{WGC|{)SWy?VU`u~?Se687$|BUeuqS6qJ>Ey$I zCOuk8e!v~_S<{O%G!>CHQR$pGRLys%*7#($w=a-U4I4ut& zy@dOu$#$uhwt2QVEN>5Rp zSedz~k(BS4IUznfBWXhB{Lm%&c}qu+UYeJ`B$SM<&Mzu2nq5+zv?VKROH%Tt^z_G6 zgltFG*mCud2H5?t)wy89_}jI`BLjRyhU@k?i ze0JEjdQ$PI_}TtvqDKdN&ls9I_t3nhIM~{j z?@}vmCq46ieP26!W@%~ZMDpHHY38wG#mF@hxR!xFFaWr)8QKg*ruTsuwoEhR%l1`{ zT^BTdP`=-|@zJAu$2(_{PdiG79Va;D*I%1iJ}e}B;J~nvfqpjK$)p)8x^^$X{KRNc z4_fqLCpXE8o`s@m3}Lb3`(vKKED5^v)-Lg$IaB#zCGkPU5##H|x5YeW4LGd8ZK`BvD`Mzm8rX;RU?bEMWmC--kJ<>bKA8iY5{(~=)`(DxX zxW2P+BjaSw?NKlCX93QZB7M>RM%MTJnI>=4^kiK{-UmS$05M7mLqf+hsdyz5116>) zUbXH(^4Q>zU6l(qr7zB3lA4~9BR!ckJ!oXig!mZpW8^5#J|;M=uxOHge78rVLdIrf zNo$7<>E<$K@Nhpe&Sg+{tAQ?k+^{7FcN#a}`{9%-l0cA zQosnkC$+t}a3AqY)upnO;J%?!g1gS!s;9_Og1ZigA0UuT7{r5npI^uzkP-~y zhBOP+RkD;|kda7J#>#<|XvtO2azRQkNGSIXkJ}ZI3sQo+hPwJ9S0hUUDWR173BQ6t zASD>Yg)0Eg0&+pJaWfgtGkII#HXx8}4C2Sl1kN-K#hIq@K(2)hLUE=LH>6pp?t(Os zYz#6IY06kR6lY_udX|ggOd+9MK3~MrP@E~GFLE`qG!$pK1TA~3M$6dUgB%YlmTM@sqIbLW;yOGO_Qa_TA;nD( zXbC+NT{xuBxt9fyWaL~elkzC-%=<7L1{Kp(8ZQBtL3!SOGZ%U{KET8VXY`8 zwLhcr&4-%*Qfn11Gt#bot>FQfr84Fk+b(nQJ`cpS9mZ<^ed^{v&<8Imeb68FN9g+I zz3}hUJx|sdTV+||{Sd03MQ8l|@Oq%S`9Hw>4Q0fR#+hcRGTsj@rT<;SLRiC|d%!5> z-+b66-(R>J=KUK=+yW(@Q8?5eX9>kW9FP7x0(dZ1{ro*U^LI9}5DKlLJOhoXGbY9O{}F9F&}l(stqoAzE4&wo6l1X(=W!TU#3orrRF4 zq)|zotPU;9^iK*hmP>pm1@sMamgbUWZsP+danG1M>rHPT7vo%cPw~^Pwy@p3d4)>zDRj$}@uYFdne)@)vm!F{qT<8y zQk!O&VU3e;Q~1Aub!TR0FzYL8Z0z9`QxbyfWK$Aw@!?i@M?`p|idv=K9U-W%Fhg{6662GV%&Pl5b?xGqYRKalj>q<_87k zhlWlM44h7037j4pnjawl1*ugVdnR@WBzp?Bm5d;Y1MJNazG`eejVNh7=8zUi2s$_T;l8k32uL z(36CD6nP#N)5)lj(hK}1Nk2o{NwVo@26>~9-CBs73k&IuglJK9vtIDii~}#>bbDfV zJ&#YH_J+IWKVFvata0*m^)x;`Pt)7$P7mrNRJ|va@b6*2h6WFc)cdfId@nBKRZ@vg z-L0~S^6J<4^B%aZeO_HldDSyA($gy}jNfI*;&+kv!@WEsB0ObY{ki!j|2J~~Pw|Yp z%vieQbw8eYS(VHEB;;`#{u|XC#Ih8r7NXyAUp4;|ZeS&<&CMZ#ohE`(jZ$XwaDJSZ z#;y0Au84iMplKVrK_04BqU=?&JS1k4OraQ*_^x83PhMvkoVFMWJQ;JzDk=G@p9So}nZo;&x1 zB)xkoC1Mda8^-@|gT#}r3nS7_z1@uVk?APykWw04hty`;oqE?edhSAZ-dSJrL~-E$ zALh*YVSnI^$4mXWa|dvs%&D}9h0^cRu^T@~$E4pEMWmd1m*Dzn)gRJde63~?lM1$Q z#o1Z+V19ZnuR*}AZGR7JzZ?Nw+y^dt9q)=Tq1xEGD2;oEK9K3n-!UQ5=$PDqM>^}L#Y>|{jd3in52;8cn?tjFvc0E- zl5Hs!A@*pICvZ5g-~f-Yv1*14LXniJVe2y@Lp+rl-B&a;tZTnd**%TRxR#}6eyLaAQIlt?2F zB85j#cMkU7 zXQdWP8nkYS76m7Du{l^7Yu%GPftD!E>ZRW57Z>MeH)N2s83Y>9$Kr`{=*G{U~P+*qnj#NwLNL$PpM<>1#DPqI0iZ1==DL-{Q~+mu5PLI)Q%uY6@n zKg5z8X?tuX{Q(svmK#sDdP+IjtdN$Uv?VKn&j5yx5gUF$q;!nLM@oMjcVm?gk*2gt zsno}9lYWn)Dp(ZC-#vtt?*`o@jem_##3@&7)ZiFo_K(bQeAeM*hck}+Ys4T4^g~M( z`PaBpEG_hPFP^h^IO8CvpdPt|o3L|56r#sVY;ESbGYMZ-^39UhYz1PBGGrWBheRaUpdir{Du=X^G<9Wuba3M z4pc&}poFiL5@@`WUJ0GWjLc1^CFrrABuOuqP>d3E<2Rm|S94;+cvn^eXSe{F7sBKh zWC-q3f&_80P33;LQ^);4MH!Wh{Ow*yrB_mQM#V_urF?Gp;-mNQWA^aTa&lxKh6&_- z{xIK-o#ukpIAc0@?vHO29?a9|Ecg@o@Vs8*XC+5WONbjbbd-P82*VwDW;{qLYj+LaZ&H+F3z+Hx^()V0n&3Yx07%2B=>H`gD!8sl{76f~F zaK@51D)m8tv5$2yMIjjIuAOpwE-HWpwqQUs^gp;88--xAH3r zHS4F2&XNX}&g{+<2#@T@oS}8I$bsQ;eva9W`ncibh3c8Ew-dBSRh+m5bE*TInL!uh z3{K;4#V!0{!yCN*lR{-4*9P9cq{Sr28xCVOe;IkGwyy&<&GdZ`$eMo4_5GF^zmu8X zFK**1MvCLO3$1m3vA?Vr+fynP|3xg+&B54J=~sw~7|8 z_=JV|c!r1bYwow4zGhrA3mZ-ASj)AF`MR1nyhCdE%PlmcCs#3wweCCqa??w~$flR1 z!Db!EDDE8lT*-MR%vc0 zsZ#hb3|eb}LZwf)LVlL7X{Z>U5!lsPPJPJq_!XOxJHIJux=ErS!!)q&P!^dQSZm)YN*+CkCs(1Y4cyGl7XO~d6e7uLr2qy;LuPw|(H@+YyBswn^HoAE!@l&HS z^B(nISoM>+mG0prj$oj1^|@#%9pM9T&l(-wQ0%Z0eHb~&=QdqAz%OeW`}qA(HV!0y z!9z&F=H{kfVVSdnWlqQc)Py|+Dp+dX!MOV8L)BG&uKEyz$B`lQ`=5L^@_u5HjcYop za^N=zzd+N4@x~hZDK6M?@#1mT6ZBnJwp{e;NqmsuW$vozE*5R-Ms5w3I+6+Vq_?FX z7ZN}5&It0Ca6uy5#oKFfo!)Dw#owM@*C^%XkaNuIa372>h+J zjpzPq!Dsh205P0pn+?S|>cKdZhqCLO4hES|w%?3Dn(SCJ)L%c8?dSe&<9>Nq%Mf}; zvC1eK+Jkxr8XBxEPPPx#CEv-`o%ewI_{jAcH{-&kB_>)7TNhY0hIr75LB2VdpXOY*F&$=FYKD;oBgoPDF9TsPjQLfSpn)8Ni zz6c+!^mBn!O_tG50kJ70KS{RqQz-pRY?874>tF#~798XjtWm(lfyU#j!S?NlEZPb9 zxZs`iw0hf}pC-5CsyGWOOF4|1e^zmq+woM)fad~R%T`L8`Mt0^(;8uvXo0bm)1=j$68*sK?j;EH9jyP}G&QlmHJ{rSa zHK@dV>W)z-ibdNcT^6~-Ew~#_eKRQ24S7FQ$~?u&{AD|x@4f`QOop@hO~?PD%y+*q zJ)MZqytv=dZ}8h#V{a(_PvW*O6xWH3_1t!L0p4FtkEk=Ctr}BC3RrBbGeT4sPy=}z z{SRk&2wpl8FqqmxW#vZ0iiln1jIJ*go)?!gpD?Qxi#EBDpCH{yXnW@^` zZcqz6QsYG3rdHx(_(0YOi>hCwhmq-4lK>lrm7x#;d^t)~AzuQ5^Uqj0>!-DcL-A`dG&-jfp z&CBI?at4Dd|Jm(WTC_#^#xWvO$XJhHIMAvdQynOqwi&)jR%TO2TIQXz_e2_!#N_jk zCCL=o=OMqjBzr>?8Kb;meiG#kwPWT8N*-PeYwpFJQ-2AarLPL!Qk+3zXT>a%@HoKYmFB=--_`&$| zTb$t|eh&U{ew46$j-|*E%VmDhwpo!=et>(h^}3uW>wEewuhE;<8WLgCOw``C{Fc}2 z8q4~OTtcOPeX|xGyK*}BsAXpYpBO1skrk2Bv)|b9i?aE}Jq=UoER%+m9!MD}%s0*k zfIf?v#=wuo>h4FLraCF@CDvA-gPl!<_|x+VBeaxd-twgvkwwVwN<(*=rr50 zDj%#utgVp-IxEE+K%39DIN7no;wc%dt=N7Z`OH}E>FP87$^J{mPkyR&!V~l6uY7Y< zQqZ1h`!2-noHPHM95J~%xmvSbdcRAWZ>n!ZXQ`({?!LLH`^v1OFG=r?6(N&HrFP&F z^rx0bt;+38+?#$CzjFUJt)AQ2HE&8x;ZPM%I$+1z<7_VN2g-pZa9bqoeW0BZhGwz5 z$<~T@LLOpYKzfPKEt$EnZbVs1P)tTYTiBz1S9PPKPy&9-k2d zxc_8t7#*XZ6|mxr1IP7}x{%8~rG#EjY|mOZaBySR<-hwq-}5p4WY2?c1eTw{?l}Yc z9eFGF)%>^5hq`X+GlX=!o&Rd?pRh3!)o)T3e;(%rQww8D?Y5}e*$Ri9unQ}!FzK<- zwJ*XlgNF{EGAJdMsJs2$C%9mod-$Y5hYm$7Qh#9AC)>^{e*BRFLu2{o+!&YS{!#U_ z`E>=4C)7kz4rs)TIvMos0$&n_1nw}mru&+yC&`(L2{yRB>$rI{cF!4B(SPx^C#0o= zxEeQci3e9ZM4i!O@3o-HcFu_@q%MOD&a%rPx-1l_T8BT`C|A~huon%hTu*`ZnX{FP zGI!``Rp4$gEVf||{h8P<{bln$>1%G2Sb%G#&*$#Tz}X;gsxvNseDG4D#Q&L>M>>_1 zl;|59Dwp`9mRYF96}8wPR?v~2+G>r9*X0tO^j>z9iv_K5#&&`u(V4vY`Oe*=wk(qV znDFwClgj;?Rezu5CmSB;Crg~VGdZwdD&vCY&)=LmZ)9oIBeAuUK7F|>*_NA22B+m{ z#7uDyn1iS=c-ZL&sL`T#u$D(8r?T6S_762pb5G}-7?tWXH@18xIV>d(8OI&zYIr_A ztm~melXk1iVv-|*{TI(`&Xazc&^V-`$UZLDkMz$Y-KOnMr<{ zrbJB}Kfookv1H2D)N#=nVS&T5$A+ZG4(u~&hpuv6Kvf-XEBFhlwSt%YZrO+FCTFT%IG=DMgXE3zM zjrvnnnZi1SCUX4>U1;5mMlWz5ic?TEnaX|0{e;!YYFa7%h&)|aaqzLcCV0R<&hGTa zc`;5p+Sm9t9&SK?y1LHcPZ`FJs(5K87b8BCv??)iRTBL*^Q8*z@q!W6FO?UhtV>E- zmr_uE5v3AWPYn%1LhOh|`n zWZ*g?7Dv+TVlk&C`42q2NANu(vPQalrw*AMT(w2B%f?}vomJA9TMZrOFGuVi*B7yA zyF1XhWLmEr5r-NZw^fEMEeq>#^Pj%ikp;a*Rit)!8(7|yIiK|xm0i>mj!KLUaO4Y0 z4j9#|9G>oy(pvwn9d6!ztE`Iox0}8bI=6VX)h-lkj3a&z;^JuCu;HR8Yh04S@2S{P zPQuETBE&8#>$YBdnuXCJ;;PlS5IrsI2F^9tUpSpt8|RybxJzYsRhTQY=ljD<|0m@1=( z>i&vk(UU`_VZ(-u8gUr2gmo?BRo1J`#;kGd@t4@xH5-8P_~$d*3`1V!*W6L?z{&h{ z6gr^IkTuM6-DVup5lW8JrG(*Nd!sR$f6_4VA1oJo8lJNll~PeYO0P#f)t2?Jlc_L; z7-wMm6MOM7YUFx;KsDksT#P*E=`RfW=$1-mUNjB;m&Ce!S_@sZRx4{yw1&n9)AA5L zrD0c=D|5YE(`$6C(Z?{B|GT}4*vdeREGY1{sEE#7eyGK`9#?817Lta|Q;Mu%wHOB8 zQ;HeuX(h@8)ep_H;J0ig;|ZmX@{wgUmuHeNaz6_zO>&0H*%oYj$rNe7e;J-lH`?o3 z8AWT0UZoP;L~W(y_Is3->~e1!TU!!Xp509I6153)6 ztEqw7(~0!tpTN9A%d(?uC9INkdOJQL@%HV+yLZ`N{>&uh*WF1?DC4ebCVv{|pwLKi z8pKNb%`67P+-^^6A{jKU-0Z{cFDsKSh7YHE3WkSsP52cShF_HSKbXZ($R$&JmD$GV zibTynsKPNfZNZ$~0Vm`!N>W~BOvD$B5tqe~7fBCgg4*KR^!{M(H=_rfsGe7iW5 zv%FH{4{72=X6hB)g)P!R*~m*?L&4^0(O)$3jz2R>bmy+dh>r?ea;0F&H=TUC9k}1X zAi6AcMyZHuC4^a#DN0V<6Jn}A*C5Wp1!CbsXX&Ml())#^GqE*%Hygr~Q+>eOoVm zOB~29F-*`&pOsSGuavkN#?PEd>%B_i_%HZfkdZK}5!vR#7AUgGg)WAy+l7+X{3eD6 zIt&fzncZzlC{R0Pj^^NrG@76zXkXOGbPco~&d;b9Zj2!MX z#3^8qcfUxAiYkY^FN{UB8b)CIc#-W&NSdoDWNmb|F0Xg&EWR6!N{dh;)uu&_@G3?~ zE=B?Ai&3y&p5rK;_|tR67rFh|hGbKQ_Xh<>p@U{69$@bbh>KK#m} zg@FNexkVfO`cJGFU$iJ7pl(`mW6*$!<>D7(V#me?Cx<%r3{K;Q1*eR1>=~36@mLHm zTz{r^G_7hpQ~c)##Sy~wX$JiL&We|Dg4Amk;CSsknXD%15=f+)GW+W z+rh@j>?3M)ExlihTG;44K04zxrKqQvS+oR~)L_4ao|{zq%BIA`O|O)ey-L4dEiFA$ zoOgOw_36C4)5NoULJ#Rb-6oYyvL-#cTO(OnnVg(`msY(}U45yl>QZ&}D^&aByAeYF88qV{F=^DhCHd1&8 zI^og~ctB9XQIx<5Q<;uM+d~yBwpo}eNLFYimz=V-Dzp;HHD=q&(5kJ%RQyS?oPKE% zTE|h9A4>Cpws{40Y**@lw#oFxK9m#behp^GYOQx#D39hUs7a5!bJ3)VYJ!(T=f=sb zOuywcTrgW5>2XuaZ0NgG8rwSKrZAktgT<~e`+S`gRQHlPqwG$-m1Yh5Lpk`301Jk%L8B~7)Ys-DYvaXxdA6A=&UG|dHidIHVq zj6h(bPLnoDqgF^K^T_Vw zYy^5M{+L^j+17p4!w$wLr@Ih-!Mt9H$ul+&!y0K&{u4eu>`MoX&+yO>i|ryE>aKo4 zJYBLcc}6IYWhke51ODTm)sxVpE~wOz!)_Kfs#?aAtI7p8!perk5qck2SCVwNY45n4 zXXfOeDa$*Yo4v_{mp+gr(y3t0hMAM2UL}3!OvgJLwN0Nzwfg_aSfFvGU>? zXIx$rxbK^)a_-z0(kr)SD*JRaLu8#=NP?G?_6}u7#qr5CmQ{WOKjxtd?8mwLv)abo zNeMnQ>h9pfPmL=m@XBQA4~AW&@R>OjtBkd%BU1R>2!(v>-~5HJSiL}*q1~v3o$4Ab zgo9)_|mipuOKawDX?%gz(`_-+K|? zfZ!gs!GS?RHa0;)g&Q{(7C!bEw=QU;U5}6;|DYZ{g8Zj%+&H~x>sDz@P_V6Sa8O{N zt!-dn!G;Y5MO(HAF4Lvhf-Bw$?rxL(aCNg=!ieO?IW=q6)XZC*+%A-N^g`l^etMeN zCwa}>n$@do=B>gSt5W)m4^*AQiVF5Owkog0Nk4(YDH+1{>L|O`U{Qg{z=-jK3~8}9 z=pg|3cI^%IbR84jo*JB=&y`u~z~Huelv)idMx^jv3tw5zpiJ+Ce)r;B=yQljSPcBT zNq;Fk`jj!3%+LJm7(0=|VH1>erR!s?Xd{IqCa4+jA2mT$7ZA}+M`omO%pA&iKNZm9 zMkwfEZfRiA^K|U}%`8490|Vrl(M|)~taZB-^J|Y-tw}{!O;bSs`50?jy3(XQfV&Cr zvD#$4K(-frJ53B~ulW4@-9Dt!i!@tw2XRbY^w$I7b6sS)B~gHb}(vpwP?bK z%x!Ni(}I!ZYKFte+$~HKy0LaMI=g_*F@n7`sF2@YS=r6-7yk&IRqJ7A`~#MsNa4RN zIC8kPk063%7n4wIb#CpXgCQHs7<|Z+C1hp^Cmyik{$pt77KpdG4$W5DRd!NN`Q5!G zoE1I8WG8WeRWcBBCEF!#z5==DZ(AkclvK6;!F4f4dvimLzr^>9zc3i?Z5w3kFSH%I z@~Q1qLZHrOGYcxUWzi4S#mspVb3C()ASeBnITWkDR^|~Vyz49HAxXbws1lA*>U(BD#*y zpGoGsgeCY(~<$h5TA|ctSjpND6v*bg%5z-QJ!Q&{8s0(}2em ziib7YL2nktDcK`%1>hOJ%Of1uXWkIQuNt!2KOxNUr!d9vO<-nU^0LP8$&gxGo_mDH z{&k!@azc1jxW=e~Gof*VA>HT%TfP;y+0M_NRL3HkXI(6rY46)hxYo4DEx?*2rHEf} z&MDGi8$S<($y#E90&pFyTI<5=vH4cZ-$^$736hZ28pE$LNrWkr4ByE#;RkA@ptdwY z8SrC43;_>x5f_~!ow2j)*^@6ZtZ^7>L!xuUKZLImrA_ws-MdwG_vj&QO60~__KXV} zK^Fmtz16tlV*5LWKV_2eRvM`sB;mW9;2l8`DNxG~lqq8P4is6gs#CiP`nUi^Ydxi3r*Z4VUy_JBdX3_E zHHquabx)G6Qmk1oy2D@8{2%EF;Z@B^woX*|(V`z(v1aQ|kvUa!Qv4znoa*m(C(g~^ znoLZkU6d+4W$o{-IpIM$m+mFgt8&11b*f0Um2re%z6k(yHlXZOI(lAyM~=!cUaYAR zKjJjvZK;54!rcJh@lQ+XQaYK=yafKumxMV&3Os|@ePFFNF2dm0GU{GV#EN{xJvwf| zIQ+kLYw5Ga#m|)=yWXpw_1>;je9vlZzF1UrvAJ=bbg_u?kop{*L&t0!~=f5H!NDWQT2@#0LI7oC?s?8nd z5^(`UKF!E&P8B&$B6Ebx;z98snWA?m1Ksrv*QE>BNv(`q7<%BEf*Ukgij)&APmNgw z76(*u;HUWxXieJW_tEstd{9m30f0MeUY%ydBvzwOC z4?ST6V+!-f)0jU#!|3UcG5Q&^I0&kM=35EA8A-{Xkjbl@% z9=ow<(GT?dhefMyE?ahU)v6oIm){syTMIi_%S`#tmmT`bGi4{5(3pXK*Dk-YswJZ^ zqG_$r&~`3`6bMia0LB;44%ZebK<8;0+Gd{C+O=1^aG`D4=xt*uurwRn*k(pCFYxw3 z<0QvDs?2=aL`4%YtHC($apRPkP|*x5S~IAnHGB&ml;aUGK>bGaA8^7xqLG|V2VF=P zpuKgw6a8qeu_mtSCq9SUzf3H;t|1wnaA*_*G9Q3^_Yilce`{H6#LA6UYpu*-N$!MXvW<+p>}IimmxjJylTw&sGWt=a&NUk zATe=EA72?Ay~7sh0v0qF(n13|*U3G~_NBJvx`3J*rQJ*gGclInX{Zw(ZPUFL^?0<@ zgAveDj~4npdY;xr&D-rzyr$+pG)KjYxTE)=yQw`^)T#w#M^FEu66yxg>S*6m4F*Og z9qs|&TlDrjZ@*K-y(UiIfgf-0kXE;}*4fd)!O>Yd!#zcc-o}4Ll{@Iy4sNN^XjjMX zmE9d(p?X@#A@doA@%#?=G6XyC?;lzvGfk?=b%zw0QT6*}GrF?&k0KMW%QBB14V&JHg)cjxGp|?`Zj! ztuxgJgQ?j&XY{MFc``NWG-;$JEyvh6svO!X#JE!VE63H*_*;2rj~nceUYLag zaOUS|M76}I#;Yd4DmfV|$f>G4)eKdMszOz*nyZ?xT8P`KR;bpf)~g;u1;#h8{5F0Y-x;5c-$uCc`+o=ASO@(!|1BKPG1TOcAvrlY z3mP8%ai!NNDoo$pl6hP6!EEItdA6Pj?owCmjd@0$JGugpdRXA+i&;uYP)jPMtb+>J-*f zhG55Uxn(4F{Z6nT_lRY>Wu|4eWj=B?F0-t(thH=}k9oW0CdDDzg04l1 z$EMNQnP(p0Fj!2Igt^5)9;Zj!4s{_kgs=TAgIYv! z)WI{iLN9B`oVQ+YHJ!2669cp5l6e&-L1?ulec-D`VT9a_6{9OS0q@WQajwwBH{NA^^6 zD6Q4?5fO}qKX}lw7pSWaAqgJ0vzGlXWZ_{JseaOOv^&+r<7tN%XvnGg>bZ!vUr;wc z!ITH06vl@J$M+!OaV9TA)S+!GDYC75-46q=1_MVzuT#y57UW_3S31sWtQGMnn4Vc+ zsJwZ_vx@O=>ej)ty5rJG`?aCikXeJbPQ@pDlV15FoDiq>e~1+nfflU=3F)zsdcbf< z-^9eekx4zs=`}HJON!K9@|9fjQ_@%g-$2(GAs^mpF-|Mm-xB(5et*M;_cw2Pf8)mY zH%;6*5&tIboG@W0ovSVltj0~VK%4Pw629=hFZAPjB7k=LA?CygL`)3Ec~9Z?c*K}U zD|8UmLO;CaIYy8@pJ~+z{l3FJ0;Z32LO-k%aadTiG9sT6jc_;#_*QGU>Zl0)Jf9g9 zaI7bhrqi*awJ_3NUbM_{S7&LPIqvdtWu7+b>f<(WAqa*xGtrS&7z1^i){H_wAGL;C zc!_W@wJqfz0unUlL-w^g2?4z}_f&`ONbfH4|~yXd8?N^6YgWH)tio}x3FcCZR+n?o{i;U zSK%bjc;OM@v6-I7JWmN@urP*^Tdd_Za!D3zJ#T0NX#ekmz zl$thrF0=^8ObA%S6pkUMW{CB@t4G?TQ#u4*2Sv&H#JuyGE&>)6Ms>ib#`g`>Nz`$y zk&~J5rh2t<9IlSL#sjRrXxO(G>i`Lu&H>!+oE7j0O?*X(AY)(IiU7+F0Y1in#R3$&v*48E^VT~9Z z7ppif-ZvmCfNE<~_p(-Yo&)Dd`P3m+fn$EC5GCn<#LHI!q`FsYE6!d68w6?VC4mY4 z*J%ZRk6&rwm{82Tjt8xz^8E?~Q-jX&Cv3!tZJ>g+3N1e!$9wWDLI{lsLLjH}bO^lf z8F+E5H125F>l6bgnMYD{+^ICDfP{%E0%FRgHuWU0hq%Pfa4zZZ5JsH0!N_L%i0}l* z%KF|EXRU4EDVNyxVqI$48Q!8sS-s5&9j(a#nm3q_j2RM6 z%U-}nlQSw0;O*y7{OTBp1m_Fy5#&!a`vkR_SjAe^y(nnPCT9`eU}yAxYQ7QA`x1Ka z6TtsGYxP{@6etpE0ttF8CRaH|rVbd_CQd{};_T?xLp za*8|EsqWRt?o_uf_*}>|)*Bdj`*1w!*Z4>>LEICbXfM`;LP{d`X_}N{W3({d(BzY~ zwijy>ib~M7Tts=V;Z$l;#4$H0g~WL-n*2q_)OgFaIoDuRhYzi0o9OygQx+J@=IJ_C z>jikjz{vfGE~M1Gc#jcmy6hNbc`q>g0F5cs1t<>M7?(6Hq%9MpeM!d?gGnr@uUHQf z2Kop_P)&?=e7)FWEHhh^EFXQG(WK6cwJv!kGl@=p+%fyTE)xb6y)UEv=zrfnts%z1x_|%b+ogfN52c^RqFEztYL$s7VzR2(b3Stq?M*&rXw-#5{&^oXt(htAIpSUJIbIk|hYqRl9Xj-L zP>}Ki-oW5IFRu=1FPTs#5KQqds~vxJvFR3nAH>`TuG z3nB=+*PyMR_EZnj4fQ}w4|R%XuSH-t9Dd!IWW#3m+Qnqc8g?<`)@~=em^{O}wd=Kt zJ5gm)qOl3Fh;Z3ZALMqiw_g#DJC((};M!$rry;d5>#@7~LN!WiCO&l;Z}nbpiPpkq z{Y=*b>Gw3J{M; zQ#wt(QrxQ!T~OpF5Mk4)te+sQ&}N5Jyi?gHyOzZ%J;fUD=#9>B5P3^tMUNqt*L()` z-}M=14!zgqNhpigYr~^XI5Wm4i5e<+OB?09b0aXETU2Ts8T$IZ43?^vQ#2Bg7y=t6RAEJ2m60moSu^(mf_*hBh z3~N@oM9|D}+OTuXx`hxbZB%bg2o0K#8-0~5L1R96T#ciFmz~#ngSjeMo}ijaX>(OR zr!h--spi%JO3{o&vu1yCYrrsl@!BXl4>kJ)wh7e;)1({KfJ6{A8<|^2=QQMC@^qz| zmnBZ>r43`+poY(%EY+~6nm~`Kr8wnHY86Ib!h@Zsi_f%>;kC+o#aohb*jf>x&Rrs& zl-ua9hBcQB-3LLE!Ka9(4TTzYt>|rQnt>U}8Pa2LTBC!@m%(a7X7sl3!ZFzgj*z{` zspB%rXVaW0f={zA?=$i#XasA|bi0?N(Z|Z9GBCu5Ba&q_pwH$I$ciCb1Tl%7uGLz| zi4khzWvIqAi^S%6u838(D$Z37Bbf;C`5*H#-ULQdsBvL%K7Hi9P_1Scduf5>8nlR= zTA23-YGLhSCEp2K=wD~V_za2Tbx6m{qG@gouPzuxVmt78?V^?!TDbK4v^>oj;pov@ z!|;G;B$8~>%!4dZ25c`Sm;)|Zl4-WLKtg0#K79ypXnV=y^m~bT9L|<1ICL#pNDlS zr@_^*O#Z_o&+!r(G=g(iE%W3-2795o)b2FC)r4YbhbTo%bDv9@YrjskSud= z9SwFQ`ZN-E?z8AA=vi9JX#Q)Tj$*VSBw6dTdQahfmbc^2_Y@A9TTa}Eqv;PF7jNH! zglPT{t`D?+sP!x#^>GdDq3K9XXaAh`@QwjKebz^P7+f*?EawZ_Tkq+>zs;)|sL%GO z9YBFbb7xDa^LhZu9O}_}h25w@ADf^N49;}1?Kmce=FkQoDoU8^BO&@K6ig6z> zZfZ8K*@_&?PPUzfpgxxA_-W8kmT2K)na?VUk8e-YwfIX?p>fyS(6T-bnY!O+9HR32 z`i9SltdDD4-nb>tA$u+PbL7)EM<3mMZ`Y9op7_|0)O!!`tBejZPyqFHQC(l{A)PeA>v63qUq30Q53~ zXs*C?=6+8jqi(F5d?NjA$edALA4N@L!I&i&<%l-J?{9L7<3Qs9*PFBx+m77IM#`H! z>4n>|{Mkkevls-hXiE9e_4QTa9Um!Z*E6jL13E2KCl>6X5>)zjF@RpBmk5j|+rlwK z|IuK>N{xtG`(h+~%}8i`479B8*lf!P+~F0&M6FEW75}r6jW=p@k}FGyjl+#dlEz3ksDlx>T6fCW_?ae>aqUlPVK zahLkcjgRgSwi>UqKZt$YQ`q|~+5lrfad3;CJha%W%Fi02y^lI5@w%DnB^EGK{XzZ5 zOr*H@ZYB#7{0*Suo=y)~FDm??Q336)wPa#HgA18-QxPFqiM<2!kZpe_>e8Y&taht4 z-s!|9BT5-1(iShC)uhnLqdM}Ca|ow7MMT)0dbX3oLOth+)m|7udy{+uESQ%4nlhtU z_53JKr|46FA6RC^1~Q&J#c3_T<~5;V+JTy=nEYB*t<8;%o_yf({5?wl_{e_#QPJtK zeZx``%A9f5fpdx-p^1)uQGLSMl|JdcD$4v*ABfG$icQSOV4L?QriDiJOO5Uq5EB{S zU)fcakeQhfmz~WrBkX;mqLULs97E>}w8crT>Rol&E!p#uZofTg9=_D=s`ez*)aH#% z2=5)89pBg9KPZ@eFgi7EahfAMJPI#_MhC|}QXEqh7+4fje1Aq_d`?b$VupIdxZt4v z_P+7ik$u7w#^%+s_l!sWvBA-yE-5Z5Jlv5mCoXj~q~$5(GId`gm#JGju@D;jIp18S znDcdhOIv&5erK|>_;pD=N$+WwdeZlOwzReNU%|j^vq04AXC(xyGYlNGCU?Vv{|^ch|hKWXUUQR=u)p*((nHp5&Tz(2S);)aJoS?vKaKnl*0Zx{)K-v8VGLDK1xv zBmd;;*H^81W7VoR)~tGc^-1IIFQtqE8=-vipw*G|>%T#nPLW?-*!0P@(?iwU|Bop1 zJj|&YN%XNygNSR8W<;|YZAN*qy0sYBzs^K0s?s-2R=kfM?cPGS*M`omojf=a}BJR z4ml`gCmI5&BV3falQyg(D$^Ttx6@G;b8pqXxdESi5|DYc>gcesO%n#=(;lnfPIg;W zTTHn#yJ_9Jrlt)Wq?iw-{`UK;+J;VStS&lI)s_};?p#1xTh$R1YOF44tGeIbU;0oz zyQQgV)261TEr<&U$8dZIBU~g-JMfNb6vU4}ePq(tMz&6IfVK4prW{#u@?_J=lPmA8 z-Cu9i?y9+^e(kZ~2dmGXt-e3_;kEU*)J*f%#Iw>56yL?pymZurv@uQxa>#T}Rz?FR zb1I#OJpl>g!|VJ-KS}*4(K+Qnef|DgRGVF&%(8_6xo-S8Uu%{kKL`SepNfd4B5fd9`*#oy=5~rIo)oBB2D2~EHRH!~wBP4V0yGs`|9ITFG z1FPNhs@cG}>VpjnmcA>wu7BsThNf1e%ip$*1>Vrw)bQ9l@YEYHQ#dC9)5?#t=m|Ix z%2_MawcJpe>deh(YF^c_d#q1YI~!ItH)Z5HQ_60TT#Zc=8sdX{ZCE^grBUn3>5Dh? z3XX4>(A0>!XMvtEpohj6QbvMcbqH7pc2P|*O=c}#xBc&X_WXVO`bG0rXJo9AT({0% zsdlKJJoq3(9*b48Z(Y#byZ|p--s|{EJP%0lRZt8a+o`TmQQY&1=L3QEE8mNnDi9H; z-~?5&+gP5E!Vd0IlW$aCzVS}!^{e-avuW)mjJ+n^Bi@c3nAlOuPTMIbTp-)WzXe$a zigEOf?;^KID*>-knF{sQSOO0XWg}y+iBIvjdt2Vp-)R6g1V^y+?HDWVMy|O$%Lt-3 zMg+lVwoIWgQB!RNeK_G-T0?C?9A>uF=}OYNmlgqx<2!_cdp^9OJTha$s*-7gB1Kzp z$-+qswiUnkXld)@0afYwgCeEasgK^$_|5foJ6M$cu4QrKO2zU*ER6 z)n|V-d`44j#?&FJ-rLUnE=6T{o?5jwecls)TeG|UcT3Aw%wBPw=g=R2H><6&yuP0h z69Q92u;BbvWcFNwOo=>J*vw5yhBmpobTaax5Gcgmrrdj1NFtr#@rwrQT3^Y0urYFFJbB%ooI>(uGeD6|G&ucw1vtig(&5LFtr z_WQNJ`F#0`zyDfp{K+1!?EYzYxcI%W;K})mo?Hl;KJVBlzJ*pPz+PLDLL=WMXwr;U z?Nk@)U*7Xc9LT)@`n2O+T%txJB$mgduUUNSu&Sa}^$jc17R`QW*NhRa(xwL&Ed155 zQAL~T>NlpfT=&r4rs0JpvmY3mUo`mc{dq-$kI2ggXEml~O|Hx-9h5j|$Fl0JDJk>I z>o<)Ul2f0aK5=C3h{E{6+gFU=nvy!dv|;lI&nGF(nZqhdTq!fNi_1qq?kibLgJfH-bEJ?oT(3=n!2751MG=4_tRzI}2w~aIc8jgLtVZ*n_9=y1Dehy$dPh;pirQVzPrY^g{#R$te0Bf6SDR*@l;6Ey{r1?e)o&kofZ2b2jM?x1 zIytE>vH#YCJ9jt}YZC^&^328uC+**JVgD@`cJID$%l->{V5Kf#7o{@b+s6`T$>8T! zcw@`K+o1x~w;?(lEo&|*r-(!+w0v*`7SQQ*5Mj#B^V_$d-+ANt9bh7CdwFch!R*Uw=>WykjNh#ijDQJ3rmI^Zbq-=XcI|YS*}l%U)`2{q54Fzin-O zY1#F^9x*QH!nt!o?!>3l@~1$aQiUnfW_g+=3VaMr6ltu(5pRjuc!1Mc`Fa3OXAhNT z#Le!@BtdChyI#h5^7g6yznS^I@J7oNd78Uju*FYH_1q+^c1%t1`~U}Oop5Zr=Q)8q zwOhnx!VfqRCW!L)p{2-1qn6?mG9S7jPV9wAw_rS&RK2gEVPAFTltF{0WLB+OC4W$P zQ*-l86_q#5nt5a8thD;7k<-$f7cRUGk}%kE09m8X;2V!c=Q+ZzT?gmwVDXb_?gaMg zhSO`;p5CzG^qMuNH%vb?b?Tw%)9#!)_0Eg@v3PFnJL@;Rvu4dZ8`i(GcFEK`r=9ZQgWwd9Q@M`-B`U_TAeur$V zPlGcK%0Z(gKB9pkPzXZSlc7SPi_Ua{g488gcxJ<|@87v{Yxd%2cg$Nn;_V}kjbyB~ zv1)#GPJL#Qb4}Qd>&4;^KD>Ee!=sNr-CT9usK>Ye{?+BX9(%_9*~GH2kfzXB)cFRi ziErd8-PaHAj_$#{jZId6vrhdDn=E5W(&C;a9%*4Egr)HYjaxiUE8cvI{6YeM(|lWp z@S7GjYoYoy8@-Ud-@+!7K27WRO4=*0LoTs+O%AZT1ZP(fae10RII+YhcU!@sxw~G^YcBfccgMfk8EN1A^|Pm1gxbu*^13Y_Y*H_IE~n?sox1$+>fdi+ z?oA(TLAsd`cEOR2K39cNa69UwGj{k%_AD4;ouGMTa9U6}B#_5ShIW@1uX#7__kXrA zQIeYQDJnK$r)s~{v?4EedGm~w1+JBirMbDK71;tS6|HBpm zhxx8tDa#9A-?{aTB`vRSzy6ISQ=j1D_rV(#fKaBJ~DpBb2q-YAfROfvmQ7+WbM@EgBcmS#qS&0 zfJSxU_{lqexbNuYo3}5MUkko^!=KOX`Q4nABRuCzC!kf4srz+lgxnk21FahBvsbFn zn5sdc;Dl)eak0Mz%>UKQdB^A0-a1WK_xkcNH$FaR^9MHuu>Vloz7;Yru$jW9>9R#Zdl+1=`O^{8zK+GsUzqcF3! zBD1zgvo@VFj(lkc#!fseV8HegGM2}#?&iFQ4+H0NFZ={K==5&xGU5hWg+jcT=~9w@#x*^f6_M=`f6iE*^_fu z-mJRi;jXmldG;u_wrK5O$D(q%m!iI_q-@$zt@O5*ElMt0?^)&=E;C7tvgb_~o8o5- zocDNX!er0L&`6Qxj<{YJsh%0Jqa-Xs70>QTnv{{)DBh@Eh4ngf%D@qx>^@5QBFEsh zMXau5#|W0sBGk_YuP;hoRA%iBJvuEHH8VvTp_UAs5uY(Rq4aV2!`1Jr7l7)w@2_6{ zKC|C_l!d*&x_xhK)|kbS>)B6po*Nf6AY|B{|6pOk4fl-}gq=IqBq?R;K4J8I4Z&f; zJ7b=oJ!)4;NV+F<;(_AG#bY9!!b8QI%Fc=r>X{E%M9APRLP!45NN4b*1D>rT_Y6xc z826l*FN}PkAt+3Y42cxZmTh9E)O})TpN0oU3hHNl(?d#jjhg*Ds~vJ+Qm`{}Yzxg9 z;@N5RNz!ywc1di0?K`ctE4&oukmYEvTX(Gzaw5*cas$x5@_OrLT_pY)dV z!t3o*u1=o^dCLtq;Z61__Zsk{`I5I>gIO-nD92LGnNfmCr9LwP4^qK{-*PIwPZLZY zd~3d&*!5lL`42nZmOhs6h9#AQYycJ4$3Lg^R51+=ALgfBDn2 zlYB_wi8+~cf!@A~Y>>!(*`{7nFYRCf{0|G*K`S5fh{BBam+7%IBBSst^?Me$OTFw< z3>)wS^((zTe+&FUW_>tSpj%b$`^owiR{Ts=!cJjZj}>Wjy#=~>J${0bkkhvsF^&v; z_x+qAOOMrfHhI?k96gdH1}$|!dIol30NRRdOBOG8Y9%dHw5WZLGzHl?_huA|=iJ-G zP3mxUo8Xq7@l?HKw2OE_9ROEI#{$b3d7Jb-+JrnA!;nd82C_$OrX7MN$8w$&2K&5-1;H`2#$#C(*hXM_h4ZHZ?I30mJ}J3jn~y@ zyx)bR-tX#h?{`+?{eG?cyhKE>>ZWShSHTfzS@?gs--z!^2t~v)j>6!1Ob4?KY(L9T zuUD5Kbog0zy}A)bbDzc1cZ(Ne9C*4TKx~(B)}b;T5Z)ty6YQm@JNn}8DfDf=B8iA! zn!FHDnw31w?qm0pKnIOF_XJB^*JX!pd zIc^gpgRSAwMWawt>5{;ISSf$KF-Jg$;1gGVLqDcOyAf{`p%P-*grcGe6N)?`^w+qA zi`us(Wy{LTmzCkKCq(-!Z!Ilt)$a)x^?S?8q&!cg@iKi1U-|wri+RCCb_YjvpR&YA z7mznFn9uSJZAB`TPWq(uxL9yw1@Y2Ok`d27N`?C_M6yDCOx?uu+MeYJU*|x0?iXr= zTKo+_rd-e7Pk44)8r##%ajnSI=iYIR?Bjd5wx@BctJQA$8u_U3j9$*L+KbH5k!)bi z%JxE;V~)Vaj7hYlv1ei3$8akfb1Ng8Xfn6-bEPruPthefOp`xm@$HKz7-l~>1_)p4 z5D-^E?_&;wthD^yPVa3s-vSTdQPq8-wI&bDk>5gN`(50AXfU6qo3zo>SGzo|?DX_h zm#34=r-|mAsKMl}*CI+WEE5Zr(<~ToIj=?JwXmq%CcQSJwY+@xT2ANT!T1{f#7gl? zNsrt^|LqBzHD)V$XK33y{vm!Yud)P*w@OWNGkKLQcjMkCax?B7Fz=}*SLc{~^K$hs zrX8`&d}`PcB2GX2LAoTb$E-M8_Y~5U*h+~<;S@BFucj`H^P|X(tF5HaoB`v4=ItaO zgRD@b=*iSrhM=J9lO5*ov*!Z@hcu+DC8P zc)VO*KW0bm+Fw_zTWX(Q6u0U3Q$8y@+qk0P{>3*wKW^y!B^9;1sv9;=$(`I(TDiMn z_9D;TiX-#Z-_}$^y3W8l8lDTy`>bJYb(*fTUxcmj@h`>FQ~OJ?6D&5hOge^EuRtCu zi>&zg^tHtd^65wLO>P1yQw57RA%+u+9Dm$L%T+48wt*re-zRqj;dCR1L;U0DvHfAy z1QkxNn%0{C^r6AmjSNUjk9CGw$GrLMO;65Fo$%%p={wW&OYR!@(C0S}9(?2H4?X{HAC zsDAw9Kh>irBV$`~!ms})8-M0?R^7g5`(^dfGZXK-WyvtHWZa$0w%wgu8p%Ei!qlCy z6_#mYF;0`B_(z^YOIv~y_8mXI=+Q@op)V|X{`n;@P|1y~H^ODMpe<1nYyNraD7FP_ z`vMY+-;F0%xo+amXq_C-E7|k7uC}&*gJKrRoeG~$n7;l{hfH5&!+5>g{7~9|u?ErY zg@3hZ;rY~e(E>+H_x+hw3*lYg!vC%n4(aGGUJL2y@cd2vT)bPk)lwmqSYRcTK!bSx zj?--B;;hvQoT;qeQ=5^k_9*=L((vCR?mAKr70YFjm z@JssPqmI$+YyE7{-rAYC6kUc3P8;}k8M|DwK?>U-UXX5XUyc>t#P+|)`+s^tsi4b~ zeZ=EXDz1(eZWHdXh*zB*qlK{?njh?5SRg)duHLsnyt6Bi&HyZe=NKS74hY)G0tOCh zlJAS1Uy|Ij)IW$wh_K_Zh+tZm!*LdvIbsdTSr8*o4bthQ%9NcG>Qbz#6kaiJe^c|Fi^~Gve^&`ED%>-sJWvtt zFMMiO)vj5+SZ@1&dG-aB?p#@YkMKm$`lit>S!}z?j;O;=utppj$=stXkKkO!EIw<{ z{nuIqF@|aUR;&0aog2l48~Kr)LV~rZPi1b|9$4;>~r>enAR6F~23HvXL;CA(VYUh;}>%l86-cvh&-0^cKO8@i4fHLj! zjpwn5o;N$D3w0QUX}yAE60T#Bu0m#adft>OGTVO}Dph8-zc4yWD$is)+4(tY6i&MQ z>l`&&KGC8^?M(rWHp^U4ycraey#Swa{kt8m4-&#m#;^5R=HBn8FDLj)D(yCg-yCH7p6wzd z_={mJ3=0G_Gvxt;mj>xs?}h!IMMf%o`Eai<|5?y$P4CeK<>du=rKQrzt_Q#rtym#C z+*8Dd+BccU9trLxmj2R2oJF8eCL+;JoeYj(5$D2iYm?#do*Fs~)%}`0PL zCT&!IuYP?!8|3-P#V$#&?xizQ_XxHlIGy~v#}DjR=gwj;s^jX|UHkSwVG*w+LKd@m z9lb5I{ZX%lSH+S$SJvL7)nBV72IcfKmj^=JhWCFv{r?(&Ctm|iO{U6 zxL2ucCC#g8?@P~ijJCYR?`|PIOm{)Uw^&n~CqDo_(HRk4Xb{nJ-8Z=3$EBYO(d-bB{b-U*dYSI6`R;)gP$ro>Wm|<6DfSPO{YAV5}{|h~@(*vSN-Lsz~%U9i- zWLXdX8}+`ILM~*+5CDBcJts z?jb%vd*~iM`r8M-Pml0b<>(2=plt_1+g2zy>Cz2a5YKZ^x{NU$b4@HsVkYhydq}&U^|BPl@&Wm;a2nUcp-8S*Fx#A78`Qgo;L(_$|N8HI7 z*1<5Rz-hdj&EMtySl8{c7syp9jUN>4wz%s%!-FDRq#YbBY^}$+(7vF-iyHQUctQ-Z z1WCg*3N1qWQ+flcm_4yNTR%>@PCICMwlly{P??^0^r1Z?6U$QW(xaGuVF;70 z|B!-;hi~qexp+JdXV%VS=BG4=&D^@PsB(O=Uwb{pHR&-xvmE#lu^bx}DXNrPrF^XR`??2gN#M$ zMlJUzfc-r08_j5>Q*M_U;C9Jw4&?X>{3rZm(j#=DM{7BQ65-w!;rI%15huJ84Ug+I zh+SylwTJ51Q_Vw-N`0!teqZoV*b8n{Do+|-L+me2=)@0;*L0nx~3pw$D z_OuC2=mbrJWxxT9fiT83y5JkXpdK)dyH`gS|aO8oOf>aS5KR-FL9QLWfA?@$SdFIJuEITMk=?s}C^OEc^KzR~jdC7? zwqDW??Y%s4W)0cU(v(iU>4Cw zp8WVqI=UkFMHo+qF%C6dBuCzr}mS+ z@ALjssl3{`q+a`LMoFLAe`nnDsr{7qZJ*j-H|}z8*}cMGS%x;|whs4}k*ADO=IP$D zEb^0Owm$@K61mF6i`+-%XHb;m6fE?8=oLp2pMCJ4 z@Cd&Bg&a_NP(F|2bZX00WVA~x*h#4^Ld7edl1O3b74`m~PCm78{Emrbzq)DGGs~BK zbmXT0no?8o!nV4jvs}A2Zh5P9{>xjMPCRy|osDS!)#lBcnc#sl;a4nm|Ct?QV{@9v zluRF+(r?P$+m}BvyLM7j>4f49O;xkUCne9=zohA|hRA`_cfTSgsBMhR_-PlMfs@cN zF*E#wSPKutKK$ zT2p0&T!fd1KOOcV;%YC?dYy=3U()Bi@Y2~ISfGWa2$F0E`8WDX-D>| z_iChd=0^Wv*X@3G`4M&F36`+-m7Aw$U`?Tn`3WzISKtZ9X{fZHoEGhT=Dk=d4HU#{ z+-GUENB3<1w@NaYq*z+U!7o zpT=9?t3B6UBOZ6xSg&;c>- znSw`d6cpuC?YDYa@Zfy2Amvl(QK<&%m$CPxc;R9Bk32^JcavMKiJ^Q6Nf_fS3`(q> zSQ;ErB>&NsW-lD`BJ&G&hNtEOcD6WE+ydXbQ~9)G6J~u@)NwsN88#p^iuLkq(6AO7 zr^I@XTae^NS^zaL;?F|!ME1mqqo0a1nMV}~-&{FDT#sEgigKCb`@Qsxa8gDzpz@=z z8*i_a{ly$5k-v>Y;Mr4bW16~HN&G{_19-XP$o)Y)UZ&(zdg_ui(Ukcb-HuR^aW zDVwGJ`ORe!MdQa8MU*uYCwEB;#bo(!z)bDfjo%4!o_L4cj^7=eD^sLT#A$M=MX_2$ zU~YL9zuow4@Yn7BtynI7LOTLM%J))y>*eh^WZETwsm?s(6F7W_Lw{eE zf8guCecOMSy%<759PTG|piERfJfGi^cEV`oy=#Hoq%pu(3nc*9NfhAgQXwEA9= z(~F84U9QHW{Gmhh3yO=C+MHTfeoanJO}?u(r((D(fB5ix*Kptz3)wvg*`;$i&=0u# zRSUi&_bUQ+gm?4CmO0{cBB#b*SLPZ$+|fU`UxRbDoR^cEotZUka!yWqM&@`54r4X) zB#P}8FA^rr?;bUS6Pfs5kICJL2(s_dhEpTM_ z8x!xUP`@dP|MMNz=7Ql9oe|-ag8I-lV)md~DmpDWgmW^+NeUeVuGnp$Ef~7QpvVP_ z92vvo2B!9j9hACwMcL7uoSf?Ng!FvHwo0)rt}1T54tvUaOMRh97jk?fM5o|dF}*}y z*jxRrAN5S5Zz<@5^gB}##nrICt;*#Nx8(xvTu>r}7nHx@&X05ln5~t+5i_lfLnM9o zA8f_|b+wh9Ex#8}m*Z)^az(38b_zcXQ?E->uB^PXoZ$DDzYzCW=K$JO9a@5XMZCr8 z@2l~47#h#&@6~t-@|Td&E4~_Uf}!!0D^+j5U3C<-50SqYS1Nz+N%|&30@ zjkihuzKh1YQ9dIkSVsUiRi`~#iA68^5_hl^z`0Sa3==0S_gk!1i+)FMa{+pWk25bx zn}qM>FHL^$YyNSl{AH>7v4dLmCHW!Y2dij4y|wx3P^&mX{mMbyG2~QHE_kT)ZP@wH zzvF2>3PRgpgI1U!u+1|TZ=T}F?KiaFRCV9H+PSl8LxV?!XVF_1r4zy_WuRHdz&)#) zlz|cI9$MmLe-*zL-skJ`uq7Z5DGzO5B(I88che-84U>Kl7h8MbU9AtI1kT)n3~N${ zU{v$FF#X7~+1s5imoufXklmT;a-}*73$4B4)t7^9g-*&=;Vd*hxvWWT!plk_xCvQP z-UPkhO84PTk$&eiu=^fmUPl?)gQe+uY*y9A{c2}nSa5OetiWD{N@0F#cv|3vb8*gy zlmd9i*d%GKSg9lf?-0BhY89Q@+vZ5|*>y8E-sc@Hln8Zmf3{_S@1Q|&re6b&i3P!V z%m))4PEYu_OnksaWCH@{yd&33Yd6j~;EPX;x}`t6r7J!Sz{jOHb-KK8OneB=y}tNx zIQzTelZLpBRosttd96mh5qX`~!k%k}pK0xA&AH&ZNbjyz$!fJf7aP^0Ri|7@D z0DIjpfQ{`k?2yqTenXYuhrOnKP*1QYUWDX|ELr+Yyi555$D7une5?vz3q$OYXY5E< zyJJ(&tozKcLX1!5?94&*M#GL(l+U>)`wE)kV_j3AM+y5!F4``yQm^mB$W}A#4@LQc zj~u#QfgZ$8l5V<8w$yaQ_*KgnEgRTkwwK+{9>K~497X!lni&e8lTDLg`bR@2R!nKY zbJCie1A2f)Zhj9t>+F0eq)Bm3VKyd107lbGe0cxlqc9d)`2&2&$#{z4-X0cVg*i-{ z(P3lrskc7!#xR?cO@;6xrEQ53C=-gaFh;;_#KzJ$>=rC2%y$$}Z4}a0;LH>Y2xF|{ z;;+kVlD_SM zWc(t|7Dn8VxOe8{w?AFyn7?phU{K?rnns7x&@lV4RY9UG33Bf!r!&wm%r7CpUNth( zUJ#eL!<9BJa#TfJA0^t)7T{ksAore^XHMB%F|Qy<3URoO zVR>UG#wl@)QzFXmC{~=?wx_8dvoB&?F+$OZKwETQnrbK{fGBW88o-P?z#v?DC{eQmWEjK2B(KB{{9X*Hrj82GHZC-1BZ$Rt*j0S z3{?C@77#L^fB(<}vzu-nY^#%Y-g#6 zDnN|sEyV9EpK{B>;r^^Px+!Ow9Ooa@KQLuvYSIGnOybrtrF&;aCq>H`F=sPcP+~R~aeTHut z#3GWML48~^%6j)Lj10_OIWKn96Mg}rf7-6^Rj~c9sXm=>e8gJ39+_7N5ACIu#yqsN}#j9Ju4(1u};ik7o5duz5V0F z^bw;Hl>U{2{8&g|yBM00B#FuP;DCN{aiz(MEvX>FCV-7mc@v6qr-m*rQHDhar}?c> z(p;++jt>k9_0La=9u^eg7an9E79JWK6B6Z0im%BL7Wj|OiHhwb+N7WqXGmsL=%4{n z{sn%$J6dd)F*E)LviLh$4)iYdDPzTw=)$-k0sTX^IFdHuHvYl9r_QMr(8kmpbUEk*Cweir|E*3^HTE#B)FSxQwGbJ& zNC{*sRw$J~k^VZVK!hFefk9zdxZMha0czg~Ed;zcRN7H&r+bC)4M3woGvYp>#vOzl z%fiBlLI9u|_&{Ii1W|G}5fz?O=q$i9XtEqD00AmK@Yo6M#;E|PVL~?7Iab+;>d4?k zl$`(Yg||#8-x)9Tju8W@o*R>z;^!Zg>sY$7(JtN9#}OA99+EaNte+$Wq$S+CTdK1S zzPV}kfzbZ_2ZRJL(O(G+45?l@sOZoGZNq0N3;d#EWrx4N5}rOd&l*x1D)cQBl!)u< z>gNth={vlC*n*Xb*0FOM!pd7~`i3QBrO4yLhhzmrP6`zg6s_x9GX_Wd*)xhlZ9#b< zLtc1u;uht2K-{dlKwH>|d?h+M-4zt#5SbL_FOX{K8*K|5Q6xa$u*PX4;>xoWmtTIU z5I-_saM_3D3PW?6qSqC~7TN=pzHE;FfTa2vsa8>0kd!(yC9r>xzqBHBN>f=vfXzQS zLWn9(59-rDCE4a5HDFL^RAz`XB}lS~ePW|>M*A-ia%$p}Tu~u0v7zC^>_Opv5kbSE zlk)vTg967dT;)nr*7&6bM-Nj<7KcvFEt-%Q1)d4EhywKS#p zLzv&7%Kl2is1fO6oPY1MVy9qtp!*5=AzAkR&Ojx6L`hg^az96)Ep|eflvY?p`+5OSs19O7x!^3PDh1I*#{KWvj7X$qKlxB1p$(A_4ZYz`g z{A>w|UwY&t+5UrELD7A4%fr#aHWJ$p+!B75zJ!N}WI)Jz`+WD1;UHOIZ z%#XIzq90+PqYVYw4mppK%_uoejOdUs$SlMU@}BLA$fy1V;dVHX*^-Mk^8a8^cED;U z0NOnVcFEA-gq@S&%1PN86e|@A?0j5cSlGkKp)5K~l&izyl0t-g1LQa{8L@5Z>45&C zHI@A{Mv4^!W7rrgiwN>d6h8J3vH1nrqQZrFy~6xLlmQ`)0k+t_3uIYw1_c*{iPjvs zC==1*ehx7pczrKFSP(*HuUN&_H<@{UW3w_TARsA25Sb`4|9%0XmO#(P9Wly>zV-}z zj=jp>W@p)7*ca>{?5ZGx8|Z8QW8wV&Vd3Be(H!VrXkr->iH31FB48~QON!;~DD zZP|_p=s?^eiz%5jE-%DQ!a@hMD8mCJlPJiCq}szY<*54qV#}#=)W5-Uy8ed$v7C|? zY!Zs4*dVLSie)h@nuR7m92OQBcS#6IirXuSe#v5-9H5>S8I*YcA|cT)D1uqlQ+;9r z#aL-eSa_5z$j=t?Kjzo}3-e1|;U6+U3GoY?To4@ORAhNU-&k8fu2LlDSaX7c14M@( z(t!oIoL0YHnPNs#K!C)oLY2&t``VP)^4QRTe*VzIm^)h@^c<5H^L$zTED6xI$XUmd zvAu}$R+H%lQwrf(FphW_kCo-##Ijh(upHYBy|bEY-zZr%=7zGJLXJ8!ot>%%jCBppnRCtz`53)B*DZKkKrG-xY&ef1^};O0T;RF?&miiu5|3 zx}+0}*aG)?KoL3)N{=Wd$PJi*tkWYcV?h&5d0{+a^COH&$|C^Vt^nJ~Y2HU^z!OQk zh6d*&<$yhy>G>#V_ci(IG;cy7w?duB?a78VW>&|kzq z&#mjC*0GT;hbP>T4=4LK4wsr;R9jm#c+#Zn4;&Cz;I;8to^w7RlCs7F1ber2&z@E_ zm;GhkIyKSlNzTtt798|feXXW=@K{9|JGi(e-wkps7SA#9E3}zFG3iYF${h)|S5qK3 zeqt% zGv*T4wRN9((_&=^(&t8cOI+)&?bbBAb{UP!!I=ImzFUvPPTv*Z!`S#x#u}`MPiPn4 z(HJ)z>2W?YZQ<#|leO_UWIR2cxk8z#v|_Mm)`vOKQHCFtsUm*IN7%+O`su@0$&PKm zO2bS=5W<;*2=^3jZl?6^&@oYDric*64P}SOnF4h-^hx}^imhBLykx5B6op@OEYh3w za`>8^Pal5B;n>zO8fO|zp-}v2+E(PC!}CJ>5ywADRaUX$%J=BaOb(8SRG4;^DUUt) z+xH5yz#@!Q3#(q0&1cT(=_b(*heY*GG-LBp&mk{Ay)%+nkT1u%Whp&=JcLUj=mL-# zKE+5gp2AjHOj(50RO6ZP+~kRvnm9Kdy-v%dx_nF zdyl&?&fT~NTu+P>&a?4sOyOSqJNPT{5V$pYZMb!L6Sz%zOSr9hYq)KB9Nc)G2)7sS z1-B3H1Gg_940k9;xqKF14tFJA1@~vZ1@1PEI`EVHHr%`X9^41~5!|QzDct9Z#<*f& z6mZ2sK~E}9iaXpaia*=}N&&cql(KMxlBL*b56N5dVjj%QpOtBr-b zR9gynxrUl(ziYq4eW|^K`&N64!QgHnf5Xo}{zd@<`5Qq-5Znqz1-KQBN^q+fRpC}Q zU=5?D(GYH9qcPlQ17px=Z^XilGhhv)yO99*l5q)cn(>^e#w+6$zNa4%MC1FeseDQ(7_sU2T( zD2%uWq)8BUqtY#`7-~pZGSuv^<=Si0n)O2cs72VRaD}2fkQ?dVor#kx%(1;5-Xb zw1-Q*O!lF(`XcvOVKs}GDH-e9N#q*vxtuRE$v%U=?ypj?LLh#Ne?CX%O0}?jo_AkT zl}DLjtU6-Ke?H^yrPxcekMJ*fQrdXfo<_EuTNacZh%r+V^PPOemlpp$2fI}}qlRr^ zGqQb8F>0vCXeQ+UJW}kv-a+(8N2F_m_O?YGx?%=p91BJN)|vve8g{ORkf())F`!``n|eHU88PQ_p2w>3+heviTXh^X$7>BT74}_>#X(ChG^rp8QKQz zs;=rTdQLr`-cs+R&(Ig^YxQmV0sWMIQNLvb80GMpH^NwJoX6)^Wm9cagsHV@scD^Q zhv|^%wCS=#E{CEHH66knS~+xf80Rp}VWGp%4qF`dIh=6#)8U50V~2N+ZjOPDb@FoZbqaLq?$qCDq|=X1bDWktZE)J< zl;ZS9rm~r;W$Ke@X{L3Vc4Rt~>2#*cnX_bWow;k~RhiQ=Kg#^pS#x%E_Hy=h4s zJjr>Ri;qiyOF5TdmxeCATo${mb@{{PzRN3D?wZ*(yQ|f;h-;$jK-clE(_Ig^UUPlu z=IG|>7UPf9;`oID6#q zXyMV(qld>~kB?bOWa*S;dX`05)@0e1<-Moj>F$}^)8DhW=RnV;p65K%JRf_$&zd)D zfvhF7R?1o{Yk1b^tX;D9&N?LP_^gYv?#X&A>$$Agvp&q0Ia@%sa@ne9tDh|@TYR>D z*+yiWlx+UIAWpyqb9R_ZsFk&TF#QGOx8>zj*EPO7nV@t3a+| zxgv8V<{F=CZLXuaUgS3Cu9bUm?sd7h=6;;Vnx|l%QhC11(>~9_JV*0<%3C{cue`tH zy=cyCu4wLSK4m^{zG^Wn9+oIePs>)zL(3a)i+8AZSMTxO$=<(N-K_!EVbF6`V=djPie0lQ43!I`$DS=T`F9n@W8@r3U4mLic~04r%00`@kN#w zNiMRz$iX5{0s;dX1~d=o5b$%rk$^J+FN>OsmMvPjXyc;IincA|U{F#oiS!QM_gGX~pLiKUu=LM6nW0 zN{lISsHAJj>?O@5tCg%*a&pO^OFk~;Q!1cTc&VgP^GfY2b*r>PY2VT@r8kxSR3>+s zQf0!+3@Ed>%x`5rl(m$tS9WIErDfNY-CFi#IcvE_<$9G{RPJ24>*XGndl|%nf`V!U zH3(`J^i$B>pcO$IgYE=95BgNzvAkz_bNPbhYm{$Let7x4sjTw_O#!!^#-xLV^ujW@wsuxqeauwQWT;EKVuf+K?41jhyU4IUBvWANPI zmBE{X_XeK`z7TvX_*w9$5T}rAA=Z$9kf4y@kVYXbLpq1_3K^P*_zjDKC1bymQkx# zt;w}^)y`DAR_#%>x72=KCrh0wbz{EQtFX>tJ;Mft zjSZU?wlr*0*#5BJ!>)%t4QJu5;d#T0gjWa;32zkMBD`aGkMIHEqr)eM&kJ7}zA1cn z_|fpQ;n%_+gujkZBAg>~M&yqu6A>H{9uX7KBVtIzq=@+uYa@0>9Ems+ks5I?;$;)o zBvX@YO}v{FZc?U6)h2bDOl@){^1H~;$i|T^BRfSVMh=V|6FDVve&nji&5?T|k42t~ zydL>5@=a5>Jc>{YIM}(sCiK_Kzi=5?BPYrdlSvlgXVM6{UD zVnvH{EpxXFYT2#j#+HX#1wv(`DfbN|jWI`8iMu!~QZs$E)lnbYOZF4w!H$NI(=kL?_r6gw(* zR_wOeSFxYE8sGTM+BIL-I$guNw(L5z>+-Jm;{xKU#D&Gh#Py6D6gMSqZrrlCwQ;}1 z?TR}TcQWo=Tx#5H+wY5RyqilmuWr_EMZ1;hR;gQ^Zmqg?=+>=U?`{LTjTFC&y8RLF z5FZrZBt9{ITKu;7lkqp=-*!;9yNRP=rO3rq#kz?&54B*%Ows@oSV3}r)$sQJx}$#)bn94ORplmhWC2kyGrlT zy-)WE?lZd2o}^q!{z)~G8YZ<#>XS4yXVl6EA0>RYOBT;Jt=ul4=d&#PaV ze$D$$?6VC%*puUi-e@_w&BLIKXQ_-2q7hRu8y4 zFwejc{LUJfJaGHKeFIMnJUj5_Ajd)egK7=xIcUzHrGwTEN*VOWpr?aA49+#U+~5X- z`wX5qc>3VwgSQUeJNW3}+e18t1P@6XvUJ(w5!*&Q8d-Q`(8%zS z@gw_<95Hgz$cLliM)e*wXw;}t8%FIMb#l~&Q8!0D8TEd&G1`5!-{@MS2aFy)dh+PQ zqc4rVJ;rfNl`%16296msX3Cg3V>XQ0Ip*M3zqiIZj4d#>&e*PFCyre=_RKhkaY5s1 zjB7n^+_-7u7L40A?!dTHSnDOh!9~^&of;Pc2q5OnS6A~vJpKyM{+aCgc zDEC8$ACiCA{=}t^Ksg)Amk# zGTl7A)b!fZdrn_J{mG1g8C_;T=FDz0C(qn8^X$wAvy@pmW)+$B-K>aNJ!cJ_ zHEGt;S=(nFopou}gIOPEXPaGMc7@sXXSbQ%ZT9!Gr_5eEd;jb|XTO`{GAI9>s&gXe z#LXEoXWpExbAF%ma&FeSrRUa~+k5V$xhv-Gn|pEY(|M+Ox#ty|7dEf=yy5d^&HH2C zv-w%)m!02n{*?I#7q~9Sv!K|5kOeIkBrF)QVDW+j3vMmc7y2zMxv;{*S_>O3j9wVG zu>Zo*3#TqzyzrNWhZkO1_;``NDDR@;i>fVZx~TJ_L5pTCTD$1LqTd(YUi4x&m)-6d{a&^h8rEW_L zEiJvY%F+f)+b-?1bi~r1mM&d-VCjvePnS6^vn~rW5-CM3N z&%3A%96(?8RTgg`D zTUl?F`>MjL>aB`jHGS2#RcWg;udc9q#n0J(?)vlYpI@%2u%`W*#cPhN`E$+Vwdz`z zwRzSKT${4?ZgSn^<;kzt`LByuH)-9xb(_{bS?{<$V14`bzpOvH{>p}28^Shp+|YZ& z*bVbGY}oMIhMODSZgk%0y{W{es+%G1{!(~p~$ZrZeI|EAwJm)~4#bGywmH=q8+ z_$BCTCd$RAb?y0<| z>z>|wjlC`Q&fQmJU+sNO_C@dOv@c=bqJ6ve9ohF_zuSJl{ek=I?vLD`xPRdODf?IM z-?{(v{#yr1A82=A(Sh>^(hmk4?09he!QBV%A96TU!kT)wT#ly)l1sa&UgP8B+xaK`=2Pv^qV zO+B~ke6jPD&Nn{a@_eWBBhOF7)g}i{xLekd8P$X9gfYLiNeQvcuR}t+F3c~sbz&Uz z>)R==Biy8A+y0F|`yL9cs=z9g+kG7?t{0S}V zbat4HL0Jaw?9tsox+~wFdBM$x`+llN40CY#5qEF%8|x6J;!f#f+{?x{6NX{R zMcc7G%&rti;68cQ;-IiN{`%gyy?m-yL6!|}Zj{f_GOomb>I5IB`?8FAt^v!zLWJ4x zr&IgIw+WtGJoYlhvn0!`w)IH%SoyD5?AhOgNCtB~rhk(kDc)n8hh0Z_4D$FlP@a7~ z68{E;|4)cRdZMF88$olA2#>F6;89EDSsm%V#s8$dzoqr4i1vS>EXw#6#bNWW`CDE% z_y1K`VdRw&>OX2bj`&*20ALjlQU-FcByVGp`T+Y}2 zzt-ok_4|_6p2yeyL49a%r>GzL3}^Kh_8S0up$&44KtEv2xc6~Su;Y>JzVI(|oZ@5M z+kZWF-J=l>z7GFa8N+c- zJ&a|0S)n+t3M#mlwx2_7vDe!@(7m8NT&TUyf63c@A=R0%=lfTMy^vnU+t%L2NQ-sS zJs-k>i2sHSML4z5ZX>8D3;iMD^1A16_i)cl{=Xv26k)W^{w@AXdf8S=pWz&l-WKME zw3v(ZHKQHRrD(H#o?~v)*mry9_9Ek)aeIU?kTJ~e7voRNFF982^T+KD^}XA5dphcS zyWg%fUWI?YZOqbofO$`Kw5O5zd8~B1^d-z5N9uN#%Eg?;+C%H0+bNLZwx7bN9rk*= z?R48B(jojyooTMi`7YA0ciTesrt;lZyDg=)MwTVhiFMY3c&wphGdGm!HWPlVDQ=Uc z&B!n2FvU$EsNR%D+Q)5_&HhMduMd@xah>~8r?1;=uWQEezqY}ir}!)t`va6`8)IUw z)8|FTF+`uYbX@(baC;h>*LMG36ydZ#_)FM7uJ$2FFk?mHjtd4!Z0H+rTUE1l$8Rz!h*FoCe3hMzF@! z;<6kp1hc_ZFcIycHUXD0uAVN#zyQz(B!F1Z9z?r(QoFz466F#G>VYv}7#INhfCLZ= z+Jk5i3h>$JQUR0(fuJDB2l9d((&l9Mf5OEB=`sTYFwg$Z@4ySYUEzP^zR>xO`@(-p z=Ms%H*T1Bf{rC4{7Y~n>E}4M=n8!-zci;v5(a`H2D`}j3!L72(6}QUHm!KXXGcW){ z*gNn7{%GiRaMrD|SYPOKA9Kt3lyeHrfDHcP&ikEriZnEa=hHgQnDZ8}9;^mf$DOgR zJ7djvo(!dq?>Rfg&WUqAvWG<05?$N z5QyilxYAz#6K=3Lx4Fozm`J}~xJkktB4b6)dqhYs;m#IrsH}r<+li1kkv>$U|5=2X zggZ*ONutE2B28D3W+7dXD&0g5Lxej{q?{tsbQ5XLh>!r`t`+Vy;m#Ln`ieBEBBY#f zw+XkRC@Zf>Q=D8?6=jtarGyB#p-34e(v%eW%%BkdT!beIcf_X}sNrnQ4{mjR7Th@U zMBjJt}>CaQj^hgmqRJe{J{DjEinQ;9mBz>)jO%*x35$5vXY~@Umq>F}`h3Nn*rS6!wo2ZUy}(Bry}6d|~C0)KV#bF9VipBMhsbPq-e75*3<&!;ItBDSJ9YmjiU=SO%2Eicaf zQTP{&@cP1EU)1e7`BfiLw@@8V#3@xoY!wkZM);2k|7H`OzEi?P%96q@qPL;^g@2TA zao-0aRmsmIg@1+!XTtrBLiiI=+XPYb-6G8xQL9KXN+X3e28-~)B3!nb37gyyArT@? zgz#q*DQ}3__9DE!2rnVRONj7H!kh=hsR-XKT&#I0WwP)O68=HLpCJ4dWlG^cE&RUo?aUHmwoOHYO(6iB&&VgeOB^Djv#f{O(oWDxZ{n^pvP_gq{*r zQs^mBwGKTcs@9|DL)H59e5l%ho)1+U((|EeBYHkmZA{OHs$qCO)K3kkXF}Bodb(3> zLeF)ok@Q5T+LWH?RHNvLPPH{X(W$m!Szv2g3H#WT{M1`?Y!9<5#SyWfJ%~nMMFCm| z2SDp#l$?bh<4m|w!fik!j5iYF?4WS-2scW&k#ObR(C6YwVNZsqT9DfT+`>i~~ z5dJSoPe;GJ`#a2puqS^<*u`!iQtC@;Kh=ZkNMXVMj`SDEAFy#?^gneh)UMU^TI~v0{PJbm~4mhUv z76X(f#0L4}kOuRG#$tLJv>c#uUk&62_I|-U5Pen&VOWENKO6j>fX<~hDZl`kKoX#M zsu!&XK(wz8{Ndp1wow`m8iJ}I08stte0zJI*vh50kbS8=_BJ8y=k`*aDSrxkAeBYf z(iTLReT~0^FtWG54SSs$;h4%MsC+xHhrJ9^Q8x7-+RyqT?h};ihCUW{u|P3a(_cfs z1C$Thwl>0U1DZpHZRcT(h<>0tQ+Ob#0MMW5Zs0on`Jhjsv>ru*x!^?xa>1WrJxPCw zsU1{#9;h+78Gern%;OPdbcrMuufDuePI3q}L< z^+(v6Y)IJG<8;h3s>jEcAPUR@vk?aSeR>a$gM|pI4DxEpA3ot2<6QK?6O=`S;P?*W z8-O|h^Xem=vkUx+IOLViQD%|y3PP)iM4~qDDn_vgvKWNL-cbg=x|^LQvk&| zfRSL9?HG0!^U)Vd`IQ5C0Oeta=BpjbgW{7IhnoyytZ*1`Wv_nuqN{)8^fVA?x}r?B;vEGuPvVDUm1XMgbitZAYgk+ zPkS+rJVY7>{crR~8k|q(aI6WO){Z04LeSr#nLt_KrX}Ogo8{-~VJP_5=`+@08O}q0 zvC@FTNh{m@bWG!g_&Obq?QP-H;Kyf$9Xb|a9T5h2kPQX8M~3|++}6$yu=(rF_k0|?N8jexF_t%kM zaU9cU&M1I+@E-ZRo(Dx9?@uBOL=6xCsD7}yum#zeY=}6a9pJ|p6ETZsRb?tc<*uNx`VDPz6t zaT)7N*P&mh`}!Q(`%oC2_fP5nTORhZ|Du=^>DvI!4b+43C+umcTzgo?cq+@D=HDuv z^R4qJOvzAY#xxY3F^>G=dNiv|X+A{%7i{C!-iI7(jJQS_2PJ4;odUGhzJ=1h=OO&G z4x#q0v0K-Zb1bUl}jby&1z5EO|0AL=Udrn2Z< zQmPN}2#_7@kge@Zw)x4HLEr{B444g@jngk6|8QXYe0-md&wtqCqaW&qHoa-5CBMWz z=4~3nux@{tguMZ5^Lix|pNaN;!p9}>Uqkp5E%_<>;zK3)pW~chnrr_2L)lU=U?iMHqriu_BEf}q-H!O zKlOh`B|pKiXQK1SPfGhOw(HCBe+|d@7Wp9mzvPo4oNPq*5ev4R!u+30kI>vSj&u8+vpa!Ub~Ov zw}ZOK?>OqZ19}X3&IUCA+RSbO)JuSIz^h6>_lFM(yWCdKfzWUKLIqZ?Yb9!%9E6!I#Yc|0n}OKf%ek3 zqx=mpYNHlyy%Dg4&O{i6(m4f<6)Q8Y~5_+i>^Ob0Le-{3hMqm_zQa=H$G?dE4 zn;SD{5E>LX|%D2HZGgwm57<>9AiGidAp zZ9nuoiM9t?QKIdGR+6YRhAK-8s#g^o97;B-2FOm;ZFoX4J_R|T!5{>XokDF;TWi{& z_SLdMcBpNmER_0+pt{!u^z2DxK+l>Gly3tYjiC)eBY^j);q5XK`i7joJttZNiX-UT z^$5@ebO-c(Iz4Sc@B5;22)x0IHIry2Xmg4B7}`RjIY3)Vw4=~g5{=p$Eiv9escd2d zXam{;dVVIx#tdjX8*`vkzYbs-=xF0-C_P6-U^Qo*ZR~({v9SvpYhy38D~JP!K{p$x zpz$^?L8<-pM8Xx&!$ul3(Z)S!PaD+sUV!ZM4)g(7n`k)TjWGglK>JBF9ok=Flz@^= zfktTtNVFr+`4Wxnvp}NWf-aQc?Olv5l4z5mizV7P=n{!G1-evXl!TJ)fKddxT!J@n zF}6Zt(7ahG;n|_9Bw8`(YKfKtCA$MH7j%upC<Rsp-iHVH6RiYk*ZjcOut8($p$!_3kHBNF5j?Rm6Z+J~N$4{h zWV`1!$nGy}kiB2pAUn~#BFOHqCE9N28yjTfw>Bt`cQ&Z}_uvDdGCxYV0{vuz?42&* z7?U&|2xfx9L$GmBoFmRtp*Gkk_~{&g=baeG*d^F_s3F0d6YWZP5pS3i zuxU^y2|dxpGfCKVXl4oh)hc(EuqjX%3I5uYaVi7g89T-)9bnm^?h-Z|O637&fl?WO z);4-)r+9Ct7c{Gc&4W_D0PnhEw0?;-Y!Nhvg!U;M^NpZ&k<Hrr zvxI61)qH zaT~N|^WqZPXK^Y6&>D<49tv0)DAftjn#xN{XphAyt}McLL+KdMev1c5XdUHr3~0|q z`**R2KLDj;KzlM?Q9^4iuOy*;8Lup%b(U9=&>oFfmC%~Yt4U~IM%M!3dLRW_LqdBr z9xS1?mWN1a5643#;u@nS{D9VIUQ0szIbK^rYcsDSp*yo-d^Ssp8)y&@Wy=|z_J`&pZ(Y30$UL63X zbc6{|9AJZ>{cSixzn8FqP&$Wj06$8!iO>%c{LMb&R1d%=K|e|8I)JB3=rdf&A))=a zl2byTmx`B!_S#A=34I+n1{+C?DyV7k4OxRH|4y< zK>ZY|2QXky<$}aOeU*z6lLEaYF;I8qvc!0Y{TZ64a-54XrXn3-p#CZ%R2_bdCDo7^ z_n@#ZVcdYic7%}zb&?nuV`?UeaT^Ld62@JqtHgK=%>q0T{sig={NaBF#hRy4F+ynp#TX+L$|n(EY#C^`ig86KEuk1!go5#@ z_O&q_im{`9kMLJej1fW`0v#x!zgAF(NlaOxbPh0OhmMdajiDnY+Fp)k6Rq#haSA#Y1lMUBO6zaQViGuY(T?c5~ zoP?%G6zYqk66FE(m_)(&RF6v(>cvK|$H1U6UrUru&^IZNpsQaz|lM?hu3 z21+c(2j-E6cGKQOQzY~`M)z3=+TUnMM9}9aU9S@Kxk}flbbU{spY$$f%?bX>&`c8g z%*5Y(2xvc|IZJ5&qPa+Dub{a~=<{B416h!d7t|AEh2H|r26Dom4@z->_BwRUsrkTP z7)o)z@Rx>SZW6T5&@e{{+J9(Nb^-WPq+-XgyFLY5s&Z01e?^4{apj7onKX1YZLUlknf6;S!E{phbX4r1=Bd z6hy&)3ffG5d0W4T0;9E4fBEEm!Oyf1nr5mwi13B z8Y7{-k=9PaF>kc?651SXy@pzX45<(4I@{A>lWni4xj>X+0(U7POay_F-CY3BL{PBcXkn zmL%bKpkpMor>A>51m6lBC*g~s<0VQ-=mZI00{uavl!8u_&~=G6Ny67cf0WSvPy0#2 z??NX_Xg{b;k??!asS?^7YSSeAK6JW-_KDgI34Z{cDWN^1HcP@ELT5{8@2Jg@@JG!)lu({5^EDg!Z%AFB018X7kB(%rX zew8Q;x>G`XUTv2|;n3Y+56-3WzE`5C(0vlx|7!asiUvI(p}nwnP@?G2LlW8-YlkI@ z0X-t2Ju=-xBoq_$sD$>*+A)dZ06i|DeY18#qBufNN)$9kJ0+q0wDy}sae|(f(B4}6 zU7}=yo{`XATl+(zWQLxV(7v1QKN5;F^t^=j-`bxN#RYmn!UsYxN)%V)7xI?c>_z>tdiQ)mhF5yF=X%Zz1^oE2FgWi-Vp3qwoJ{)>mqGW~Mk?;}F zyAmZE^qz!|gx;4Z*`W_4d=&JdgsvO3M-o07`dC8O5ZV(79|L_Vq3a3lnS_spK9|t7 zh4w-M zXF)M;2&E7dV};8QW%OcLGU?Hi~~X`0!7~wd@dCIO(+3S^fAHbLD8>-QWT25 zB=~$N`j1coq3AP$FMy(-2&EVleM9htQ0fn$6o*nD0KN!Hb_YrcDA^j&eFUBC3;1&= z*%Z+Ay-s!nbnUB??Eqg2C3^v-G?Z)v_%bNj1<>`bPPPDiIh5KDl(JB2GvF(r)J~w3 zW6Tr%PtdiLC;F41YpJ}0B&-*7u!Qc{<{ctoJ)lD+be}ixFbV4k9WJ4Jy?J4Gf<;50 zN$9(yyl6AQQ8rA;%qEnJF=TcCuBaRAV8*yGqkmP{%ZxrWQ(vGQvjxCDD%xp=ZOqh` zaZvP=88%R>LD6P&C4|p|Rt7Z?-WVDR>LPp@D|Xf5@jQ_nMBzHr8uB$hPIL@ zzd+F*a|fK;71|M?zH~3a91pr9JPR}d^nf4zWKIOIjam{4o0@yWUmMy7B*9PR_XYjn zZwG~q%-_S0bIgMP`b5PTHID*6pe%}?2&N%C2s$00tqP9K^T9HNBQNuEuomHmpvhnz z!m~lwOVpgu4HA`XOzj7%7nIrzRP=$F+6+{TWAhfU6?vlG=51g*{Jo*nexOjfze-G$ z|4s>A$D4OaOjOoxi77vHkHkdz@0F-!q5C9i8R&kAS`K8lfgZpG(v}&=(T5FZ7j!?#q~8OYlFInE4HOi?T3Q% z6KRSx)wSIeMQ%}7TA=a>s||NYC*dVi~$SQT0(`LET|u$!p4?Bi3ZzS%7Gx9 zTLM~LqN4vTwIp;8!xAr14?q(E?5AQpS^7$7Ut_`eCTL%5=`W#uyybf^0O8KiffA1P zSO$U7$Y&XJjD+?|ma!7rYg@)i==#7i9!x+!9J*RU*GZPO61sk}Y?aXUkY$^Mu9+;q zO6Z!&Tal)cY#io(4ND4nuPW--qR(tck!Mfq5X>Y3JL8qypzEOi03 zUec;d=(@p*HWRe>x1tRMUH@6peuAzqt!NKH*Hu>7g3uO1(KdqiwpQ4YpzAOz>_X5r zuGLjS*ArHE30+TEVGDw;v8-7obnRpfi+Y@*I3qQ30=2YTTAGA*xE*-ZH2~2=vvL%PD0mk)*%ww<6DPHXfJOa z28N?P+n^)BNcho*)=^+I{F|U-By>$+9V?-|zm@C==o-R`IZ4po-?~_$J%>{L0PW?i zOC@xV!MaRB*UHxA61onsu8`0*y>+F8t`)4SB-(uFY6;y}u>LHe>tO2|3Eg|Ju9eXB zw-3e`VHAfd5+e+%N{q@-O+tHFA6;U!gJOIUMhp~VnxN}2pBxgSCDbCJdkj9_61w-` zlTSi>Vjo|LfzL7@KZy|u#dsi$2xxwZ5e3BGLt)M3*MpMRMHi6L= z$^rV!=nO@F<i4g>KkQfD^juQOOLYB`-VnjnTNsI(&W{J@N z>MSuTL0u$9M<~_=!sr0SSRjllP^=GxQ3L8BF+!kOBt|gQQ({zyV%;E&*3fJcBMzEf zV$^|Rj1fjfXikYy6Y3=~VxhS}ZltLP#n>hA-x*oHyb_~5)GRT&LorqfqZ8CyVpN4% zB}N6PkHjbsMQ0F38>p|us0Q_u7+o1dut4t%MSl@`3KacD=>4GRJ3>DPMIRFSBd9LX zPeIX-g#H+cekAnYpy)?JzYj$}68do{`jOBdK+%tcegcYqBy_ab7yU@+d!Q~7eLEC= zNa#nP=tDy90d<$?yP)VtLdUx5i+&{Z!%*}ip<~SWq7Mm!+JSx~^mHitk!zW~iA(UYL)Ji;JbqE89^1JqxlZ-eHS7}O^PB>HY>L5V^ATu7q-2`wzqdqImx z^h?kHiT)f~RHE;M21@iT&|(t(6|}fSPlc9{=!c*sC3RM7>mAT zCHi}4If?!n8YI!LLd#3^-=P&GdQa$g68#FaqC|fQtt2sMJXV(I@1RvA`mfNc5`)Hd zHHm&5T3w>Qh1QVh7oout{TVbwqVI!-N{|inttrvpKx;|#YtY&f{XDdeM85^CE7A8u z>q+$6(E1Yn0JMQb9}jIP(Fa2tfyNjQQ=nlIeKa&&q7Q^dNb~{FCK7!JG*Y5ZhBlSx zKS84;`Y32Ki9Q_KT%r$ywvgyUp)Elx)L{fPTB47Gwgznw-XGdlq7Q<`fOZI<1Z^+T z$3i=RjtKt&+DW31fp(VY)1h4?`ZQ>)M4tfd3gR(GGDEvd^qWwc|3JS1?IF?ApotRw zE|kU)(4RnQJ^=k8w6{dR1MMTxk3y3q`e|riiGC8=Pof`$Qk#K(5Bj}Ce+s2O0QxZ~ z^$pPffRbH+PGf&CfbI2SQ0hydSAmi(fL<9&_5yk(DA^k56`?dffKGFQ>;m)(P_ik| zX%0=4=rs1J576g2jXN3#K&Lr31FQOk<2%gYJq85#cEO~8y$rnyYO zz1ReflUV|DW<^;!HUMvN{E??Cx$xe_ZORVika9%1tU9QfRaezh^;b))Rn;15Z*`zL zMjfY4R2Qf#)MWLDdQE+fzpC}og0yN{l3vtP_jJlTJn!7R&&?*Yt2wJVkJ;Z`)Lh0~ z$y~!+*WAS1)ZEP6!raQ-!Q9RKy?Lbh2lF)ZJo7U1TJuKpe)CE5@8*l<$L1I2PZkGD zCX1IPuf=Ndvjkd#EY&TwEb*2k%RtL$%LL16%Ua7e%dg&wx3hN^?`+;)-g&&O-ub)( zyu-X(dbjc(>pjDJh4%*URPTFMTnAfStsd5_RxfK_YawfCYpAu2wVidWb*&GsiG19A za`<@r@*U+n*>|4rD&Muf>wP!-Zu8yYyBq)S@{sRQ{LjnZ z@n0`*`rh|_?)%!$!_VSZ#;<~3WxuL^(SB|H+WU3!&*IFH3Pc%>Uo9kMW)en$N!1{i$Z!pP+;b(m@ik8Ve>Y4e`0^!m5PStnevI;Pa`lx ze6&(p4mv{IRrRuZOx>mareaN`pHD}@%1PS|og7_yd7i*I%Tqyq=zRF%5H`e$w#SCVy`9 zzk!<3Puk8K$!YJ>#-=Sz3r`Eju|G&lONIN#^^w=VzlrtbdXMYfZ@OIXa?|Ph!0Usr zV`V~Yr!>rV#JvRv06r71uerVq?jQ=MpS0qr?b)wljS5s3{_onVn-E}oSHOr-0mw&i4jj_vE zgBbh$qkjRv@qUB!vA7q4#f8U%aSGOH^@Mr`?s-ZDJ)>SxA4$J-)m!Qd75$<)&@s6h zR(`D_Kx?%1bl(jtGFCRadj4-ebXEQ3$A~nd4cOQiXG}G=8E6gsDaHlk%9k`E3^g<^ z3Ex$F41FH_^~X47;PaDG()q?6@IeCi9r;Ymq?piV6YNZ@vkA60l_gBgO)X6;8FN@p zF%H|v{qp0m-T}J+hs_l3aOz9=w|pYaP6v#?j6d3N^`=%zeTe@DooW=)N^7d7srR*C z)oYp;#`h!jx|*i#*Y;@p)Z0cu^pG>di|APnX2ngV{Hzcw&B|g;s?4ge5Z0K5vj`T& zTC?`7J3b|Pvp#r}lu3Q8IcP^UtMP`7U_Y{-*bFv@En~~s&y4=#^)9xT9cD+^DRzln zVW}*Q-D8j0JN6#`oQrcq(~T0Ep&ijisJFDS+GK5YSyI6hJh0%ZZ?#z-{7`w~HvXN{w`+<#N6WByHl`Up-*#fqZ z{leC>jcgN}iN9R>gZ;*SXBXHRZ8tm5Ua%+Z8GFtZcA0DV+#JVLHi|j0@ywM?W*%%B z%fhBJH#UW3W3yOxHXAGa66VF`vAk>%^JYs~E;b)a+)9>@tziCaHS=SuSV6Xy6<}*v zDYl)JU|U%L+rUb)ZLAnu#|pD8tPIni5+59SqiJp zjpuoJ8vJI89W)2uE#%NntZtO>RcP1$u8$*!?x>;`MeZnGBb7HiIKvKaP| zwPg=j8+Mq-$!(!P>7RO$*MD~&OB-Via z$y%{HtQ~t~TsN*7AC1?>CzE2N8}E#p#x3KH@xXX!JTmSXH;gpnzH!^Qt29@hD=m~4 z#%1G*(o%V;4p&~`jm~ehA$aG1R#SGRu{Kx3*V=}c*-v{yQ)TvhNs=vH_ubhPqLX|23h+9)5Cw#rAPqiQlPDV~g#;-jH3MSHyd>zvI>M-t1c9&DX2(j%&PM3IE%D6W`2#!5gp- z@ctOxtRda_TfKi9Df^Hd9}h18PR zi`B+E#+#~9YCE;P+EeYNW>d4PIn^Ahmzq`eQIeFtN^hl)($ADr9fmiF=QsJNWz{lj zIodfZW0bMVWMzsn)s)MW$7ELPs*RKt%1ULKvfPy0loxLt@2GZCJF8vPW@>Y_gBpuH z_;zIrc7+>E-X<&FMV_Sg!9K7z-gmxES+DF@4k!olc5*MxtmW47XnEBK*v%Bx0<}U~ z5iLL~Y?L<2sQ0w%+InrV=B&B!oZ2;Qowi8hnxg%rO;X1i<&1cvo1R%WbO+r@chOyS zXWgVb>Y0odMswXwch__4Idv~Rml3X=*OuZv>c{a$_2t?EZHu;0d!qfK&C>qRc4{-V zv)U_dhL)!7)s|>mwS(FL?UD9W+oo;TZfG~PP1JG8mlMkCCqtmiS>88O;QZH1oKXogSi2qVhKZ#2>_YJX}Mv@6;r?K0lrvqoF1 zJ<#rH_qCt3)!Hg;wsu#$qun-I8BLA0MrWgoQOl@p)HVE#AftfM7@z$KMgyag(b4E& zR55B8Ax5xK-DqvZ8Fh?`MolBusAtqS8XE15?nWo0D&7iT-e_Y~GrH=1^%T9IeolX+ zpVA-ezv=h&rgx+1>qi@%b=somZ`d0n0o?z&Dx_(wqG*tbgen#(OWYRzBI}8VX zFFx=t=t+jt|KaY-n_Z#;= z?osy@x7~fq{X+F{PrAQV%01?O?f%vM)O|`>?pN+V+}GXX?jiSG_i6WL_iFd2?nd_p z_ebtZceT60{fT?Md!2i&dyTus{jqzKd!>7oyUM-IUGLuL-s-M%*SeeB+ud7Kyy~eE zRHFNi`?mW}_h0TO?nmx>?(^=;?u+hW_kH)@?h*G-ZjoE!j&sMlW88Dy(e5a>)Scu` zcBi<-Zll}eE_R#UIc|eH)t&2J`6JJ22AW;p|CwF_OY|GwJ{{SA}R#3H}GeB9?)&qDY99@^?L zVM7B~Lu;-RE;Q<3=&0|k8hqKn2fg|)5d$qX)T+hT4dP&nJSXC<=S5GE06ja*`bs2< zB#~^LjV~djTEj(}bwu=n27LiG%8Mdh^cES`2+_wHDKf2dSP%4v{>-)fm|ICBWWyc` zSTBh|unrbjuaJhYZo@l}zkvM{ghtJ?LeLjO@pN>)7zT~|4fM)zF~TaqcNWeOxxx<{ z>s1kebx~)%CW0alItRK1TD}gbCKy z&?{5L#nuJTDbryq{n=_0Gcf-x6_;4;&?}cghy1|05E|r%)+FeUIo4!ok1A-6YFKqs ztcx&*)!M@gLM^bn2W6wu(zf|k2H!VYX(*X?^vhA z<)Q`F*CnDAUzTVWOJJR>6icmD*43~smWk!~zQh&cO4uzk#Z~Z1{79^V?J~>yP+V>8 z6|1cuifgQQ#kJx(u}1t@TrX}AYsHQD`ozun_Qb7XowyAa=@zW3eq*lefu1LAPdfc&==fJz$G@(1|6ifo{|3GOcj)wg zK%f5;y8IpJ@pqxa=?fVjKv#bRJ^e9s^uM8>KZAb$0=oG>(92&#Cw~Kd{4I3xclZ>9 zz!x-Z>EQbq3SY;Ff$oi!aWY=^lnF9XCdp)cEhAN?$zC#D_J)6 zmK-Rvmsvtg^v zg`GAJHd>9b;bfhxCmYS!XR=8)%gbepY?W=YT`tjDm9*;>@=AG?Tq%DfSIMj8YI%*k zR$eF9$REq=-Jx;c0Yi9`w=YMkJ;w^On#29o@fgh*6m4Hwx?j#c988$R(-8gudb(^0N+uPoouIQ+ohMbQZittWZHf0e)bu5e|vzPWe>Eo?Ll^q zeI~q2L+qjUS=!1OZjZ1>+UMB0w%-oeL2dQq!-gq@6;o`FvPawJ+GFgo_Bgu)o~bgs z93H_+`#gKReZD_D1`5dz1Y$`wsg~d$WC)y~V!U z-U|Qaz3`@Ov+uVbuphJ^f;aOK`{(wf_G9*T`xo$RK5p-{e`)Wse`W8spRo7Xzqa?< zzp?k(zqR+nOLV|~(mrTEWgoJiwhz-v6`s)N?C0S@`U89&FWN6*o%*u<3f8NCvR||R zY`<>*#eT#7tNkXtOmEqL$7=i^v>LbHw%>v8<6Zkb`(O6^_6PQd_D5K!e+>WLzwJ-$ z&)^mL!v50!kNuVXwSCh5#y(|#Yj@b+IhMBLY{zk2tfzfgd!}K{n~rs723EqESZnsf zI=zPz>%=+nWdAvdPLh-Cq&TTgn$yckcX~S+P9Jz~`x^TZb|h)zY*>*w&Y8|&XNWV@ zIm;Oadvdt8D9?dy>30H7(8+_>EZ-?`3Y{W&eMdQ?t$oh9IPraqGZw4HFP(8tiBk%1 zaJf_AR66H50PjD?}mMQ4=m;TV1eHc`}slG&JV-B{W0 z0~YyCSi`%tjr;`c>R)TCd7txJ*ww#t4!~D)(0K|zo2Ow_|K54VdDgPwBYECA0$cnA z>ssr#md|<7c?oBU{?U2adBwU8C#k;*tNbA50=xOI+HQW!`MYz}`3Kem|8&SE zKkmE>tNCBrj{Xpq`3YF)pTK7S6c+mDu=Kx#b^aB;nRF5!qL1PE*aL6It?*(DfPZ5H zygm=YFSHGQqV>)<&MD_xr^ETq+U#2JoBYhW-xby-SGuV=Z4&Tx4wp%l0oq`%FM$oe%w3KZ!xh@*UI~kQ6|D2su*9#0MNZcE^{~^|!VbR)cKa>b8i!qO z{Tep=25rUP4%_@^?j7!(?q>HccZ++syVbqNz1O|Z-R9o!KHxs+KIA?ewxYMYzi@ZB zkGnhFU&6XJR`wpOM)qQ5vd{f3Ru{i>4`7{g(0vN4g{NWF{~jxqXR)Gr9=81-u!?yR ztC~N;;(rAzmOo+j@@K3p{({xYU$Hv*8&)8H$6DkcSbh8xYlL^O=6Dw?gnwae@B!99 zA7M@OF;)%##=7J)_jC6PtYrR!)ydabvwVZK&bL_qe5WiWlvK8Il&h5TsTkEm#i}@O z^`VmRHLetus?t<1m9BcL4AnuEUoF7OvRT0!GU8Am5*Qqt?$Le}@gIcR@gn#;Gb&I-Hty8zD_39^TgZe2v*0-xo>SyW> zb*I{_?owOS-D<14N8PLLQ`^-2>H+njdPqI29#KD6kE+MicJ&LjLp`o`s$Z&I>Q`#F zdP40{zlPuYH)@~yt=g}Crw*tm)j{=?I;5Ufht==ZGwNCR!=Hy|`w!{`^`d%7{ZYNF zUQw^AKdIN$pVjN?FYuQC6&~-uskhYM;p_VcJbwR#U+*3G`QC-6?_copeZc;{kJTsY z-|AEKnfhFP0l)5l)K}_j_yoUEr{E*(P~X8nF5n@zeU8udDWA_5Pv&SFx}T1UY0)iT3cUuP|ko4 zWq>csH_(^u8|2IJo#`9w8v-B9S-xSuvwg#TBYY!$=fD^5_XT`GU!E`I%l8$)BVXhz z_Kot5_MPh+;~VQ6=PU7*s*-svwM%M!C5x-7TbdeuB~1&O8fzE%N-CU`sTUOK5R#jbH+t{YctE+&GOG{H#o2t+>RD}k{R)o=f6->3lP>nk;Le1CS zSfA?;1Y*w%qdVj0Rkg&8kKoAjC#ds{eCIQz^9?0+ep`J*O>NwS2(lp<%vTe&!TwF76^uz+XrL_$!JkoM|YWniiEUKcIyR_)FAu!+m-u?$f!*(@l}x=`HmT zbh<9My2LQNB*L)AB{lW6Ew!!nt?H5mEmccu<1ULNs>?J;&D7aqXNK!Mp-e+YHZ)Z? zOqqB=f~lc!baLlZQ_OIxq2@(Zm1(Lfmb;3(QdO;ywK^hBY;{-wRimp!)#}WuR>xv% z!|A?SCRfXSXhDRGY1}|Cc0m~3siQtr7r{~WnsASLE#|bT7s&dBzIvuv&%LQ$SE^}_ zU_so%NOr>_SP;KxK}&6IV?$MAO?|a$&?Qn0QLPy)a~dFpYBYsytZHs*ZEI<2uB%mz zQD}Mjb}d@5$uxLVrv`5_QpGhzb+;D7sU?a;s6e$ECaqoM4ET$jHtJ?=QRw+W?q;Q` z-EeL1#I>F4qMf^0yY6P~rkgD_jFv_i^;jD2W=l;sTOLVN%S|_1p|i!V2scYYwT5_I zCBf8EINH=X)f6wBYN&b9*kvOZw>PxaH#aPgtsmK1)zCJlp=oLC!pLny_%>$g$kyhn z>e?37GP1Qb*Pj^4JF=~*b$;y9IrtyhP`{vxDk+d#P^l{`&!5XzKVQvQ&GVbe%**9# zk%yPZcp-DmWq7WaKcCYJ_^RiH+&q5~9S!c>^qOfaMCXoB@_E;K}FFXZ`_}FTir;dU&4PUOjkxSl(QwpUeDmnNKd$ z33&1`zg(6-pUcH_W?nwi&1ZV~OedfD=d+yoOs|0R7cjj7&R@X!3pjrfrx$U05vLb< z=}fbr#LlrWu=vL4ehO;pvlRWDEEJDN5Y)mASzEnCVI zOPOLROH|5~N)4ru*K(ySSt(0a#*&qBk0|4wP{u7(#w}6CEm+1aQN}G+&iTt(j&hcx zoaHEIIm)?2<;=gF`B!lM3eI1_`71bo1?R8e{1u$Pg7a5${z}eY$@wceeDZ}^A&oZoNwhm3~L4f#30-|!Fd z$PDp_40$85kmW06`aIG?JfcDY&hL$cAeTSL?HA;F2y#1yyqU;L=lTh9`-V7w$V=yX z3v#;$x&DIO{vmHB;(ie1dJVDMK@aZ589&JF737hd$9(gcZyw8?=gH0Zc`R=p%bUk? z<*}T3EMJ}{pGTkh=dpZwELX_G^W^sG!Q;d7hM0bc`GuHIi0R~c@-e><%b(BXVYQl< z&-C+|PCoO`XFB=JFQ4fYaQ*_WhXT%D!1)U}f05U&oLui*R@oWFweS8)Cc z&R@a#D>#28=da}am7Kql^H*~IO3q)&`72HS5ZeMFwjDybCVz-^VTg5Th;?Bo*W?f7 za(=(zA7UFM3sS-wIq-N+weogNBs{y=5SWle2l z{w{J$8k*~>oYLC1D)+pq#fz)7jtW9sRy4QPH#9XmGm&IhAbDCH?ws?nVstO4YHqH= zvTX6Znkso=yPVW6FRjPos-9Mya!S2DwXVs%xPHOnDtlU0yKlN7WlyQAx62TwwALFo zB}K8Ce_K;yQ)@hP)R7o))Hgkdp-E@@Cc-pzBzE%R+69b6=$<{B$Vgt?FlEaj$d*Hp zEruZLy&&toAnUy#>%AcBy&(7cAnVT{_ue4u(ID%yAorpm_o5){vmp1PAnUWB=}rDh zqqlI?t%j=}HMr{5$5oFWTy-nrsz(v7y0!h4#%{os@r^x!IMXwBguk*-k4jt_ZY)&9 zIiJyIh%+Cf*AQnuyaKK?z0+T5^dzpF-{?!kIlq|&{FTNY@mCuCh%56qdJ=KYZ}cVN zoZsk8#F@XDO+b(F&8*_DG!`AMOt*;ZuZZ!Cg@<&eYb-s)nXb{B{z{`aapn9*KO)Zc zALRT-KLXDAO~3J1n%N3hu4glg`74dy!p zA+DUy=y$|f4r6x#pVN&!hB)&zmbJgq=rvrqoJPMP&T<$%hdB2$qwgROcgrnaH2%2&%%&3Q6BPN+i=tv?*JoL0Kag&2Z(veur&D`pO8x$_Aj>Mp_`i5sLqbGuFVFU{b z`jCsSrM0%Ep}n!H4K5-~wXMq+&uePvjTL%ZH}C;oj_*k~oLJ)qS>py-;|5vd23g|< zSwjbTEfHi*9%Kz388ao_i=us@e${Aqxli%{Kh6koaHc< z8|ZPmu}v{|a=KYNBF^-T1&2A2`4w@w%_)vZmZgQ`@!zdU3V zalmf|J+4~lfZq%fT(v^ORaYvmoF2&Qv7)x6X(auaJMs)BgkjoI7=uj_bJMo8$+!;N z>R=J;+aB|q+FSUpehK5X)-N-7t(bco&24S{g1R3}oi=c0)2y_!`ia@uf2K!>-7pWjH9X86@z8k0L*p49`quE!h?)o8nR;Pk zJeQZ8x$GRvE#-PK6BpdLTrXxqK%DEv3|PduFBl^z;5P#jS5vQkGawN+_3AeR5^+K*(zaV|OI%eee(PHojclmy*^IlU8uoBAnsIk0wbsI_(fJIZ zr(wgmi5?R#9;RxrlTqXIU@+7#X!NM-EeVb!&8wjF8NL2nq>U$#W&HL7l}=G}V(5O~ZgvJ5ez(qLZ6j!h-ul zvGeN}w71mOU@KAAL4{c=1S*0hJ=+^=P~X)}NS@aaSGOG7My5Z+GZ9_ZxY|a_&G(DL z_dPfR`UKx`J4VQI)1@qEuWx9mUECC@fYdN3QUw~V72A!#<$Bg=8Wcf`Y6_YMqML%^ zDMpw%o^;q{>C*`mos!NeRoK)r+i`kZM%T5j{5jaz(x9}c>JJ0^MK{2lsQycPJ1J(Q zM6>fiJcbCX4`X$@XpR}3Kyzv@Z?9_53B5ZfG}N}X8W9;D9%n>9nSqh)NqS7oF(ZRe z(xU+12RU5$`_qIJq+}2 zG}Tlu7L`BUn|J1THyU+-7Yl>KH#)snI2}$YtY=KONDV{H)T9d;=?HTo(?-`6>N;k8 zQ%c{cJW)N(aE?lgYPBe6R1IfDfxW_?MkUgCnNjFbnSQ6IM1<*kdSaMlN~HbgcqNJgMTn$DLBqMzxt^kCQYhep&chmz!p;?HdLqHK zb}BHApg=)IQID#|rZxG=1h_E)1IBNJe0nW|YpD-KSqy86^OYp%l0&u4Cwt1XG|S=uu3u8sP}^8t z8&|um9)?$ATYXi7$yQPngGU|U#%XMet%qfXNW;9yZCkTO3mWfMAZWZ@xEez=XjVpu z8^bkdR!lJ1^-2%sj=2UHKTx8*b%6jI_5tIK4Fqz_Volpb3X~t{0Z?oEyw+MSBCiqx zCFL=-i<{e)BO$h-X+eE;6+O<7vo_JQy`(fcHvs&CX9CXndo% znpO)MpDE%-${=@ypz)caRA$MQTVSq%V19f{Ej?0Zq)hN4P(qNcCwxyV6AHrh$eg$p zgT_mU`ZKK@wpZ7+)m616c&Ub^DJEBbAWXzG4$Sl( za3w-Wm}dsl>trQ`Jy1d9TMPG#P)~HE`o{XU<=RY3@aA5&-?fQg?tRS-?JyUrtM$*|Lis+!{GWL(HQ%Ja`gNIAX<7UsX#>)6#a+GyO#cu{y4;IbAA$ zQDF}aqNN8zF!m`ES%D16H;{QvZFO->FoJI!AOXK|fZ)kCUS}BxTEK4{XtzPXJ0^?9bJWtap zFpfmT&HApuI35t^xz9M!5jP#Sz&IKaH_L@Pil^-sF^1{DAzs0U3JctMCbc;V%Q(;iA+xE1tKl2Mrc1+o#>YSn zaSsmhfD2)oXlaW|FA8COSyj_g)z~(%X=!cCM6_#4Cx|XV7-@Plx)31^^N_-jlE#`a z3GZHK?*F~0I=Nd)nyRV1D6(gFN9lA_oiAL9NP1^M{tNZfk~@{j*U*ONKWl1T{p+h) zWUe$hhRP}xjk*RiHH6G=aUf)Tj<^~ZPRRHi5jT@c$oM7^H(fSleBpr*chL}c(GYjh z5O>j#*%t%biXQciOQJcO9VJjSx+7$~gn^Lp5&~{IZ^(G*5$8^1y!D`H21CerV*{a* z3anVM0IX?&MlijV7qcN&Mye?xN;?$%`L>asAkg(aV{$RdqN>Iu0!na37O3; z@Z%~lj#K30@|aC7q%$A0DTX-9Zycz=H}h18{X`+-@CBS3-E5j6Ur7&Bwey;man1VA zSXx)#R(mn}d`s;m^=)-io5;AUDQjwJgnnTxro$R4#Og1^>Mz9RLWs?c5YN9M)>k1` zn<1WGLp;BRczz9;%|LXS(yT7hgvb3wJb!dW2u}tc!oV&RG=d&x--i(yx*kSiTT6Y_ zg7)TVxWE~~L##AEp5O!stDaCXKk3@TTjdp(jF-Tj|k<#(=~p$G@ZfW zTJXT8S6txwl!xUp`y_}P>n+4Kd&umGV>;maGJEHs!^6_-w}2nhG5cGHbGgjkH}JWB z*}WTL_ixDTTcA8fo%6GO$j`%@%?Ex45O7w)>|_j?XU`xv(>MD}kk^Z|9K7WaGJEup zho=Lxj|6aHj-TEq;Hn2RYUk!(U{m`ThBE z^J*I!qOtS1=jL&Z2MbGkVh0M|A;#*32kU7{s-0Tf*51+>oi~^p>{V0MRyDD{aZyEU zbyc$`M^8MSP}}Ck(oC$fsb%rBrAo~+Fs?rZ>XXrE9Z3Un%Y}yHKv~xT99YtAkR=i9+CWXRv^eD zDaa$o&o+^tZKR-iiYX8*t4M6X&Rvw8nT_-?8Pw(evTGV|-J$yx8y;mcR{F-_}+3K3EpFk&ofD z21=@0Ov`Tg9(ZLMORjyhuuX_cYsH9)MCa-CH|-?_eN|Y~w&sR<=#?{VHN-BiZ^U9+ z--36-bOVi+I!WWQ$BjLb=c0kv} zE}4y3+I_4!^w#*sog6J3c2~Tuv`+041;#icae7CAqA6rX!6UaiOLioVEr&3l=-h_C z@km8?IQB}>o{{!WkpyNW({=%mWPNL@o^Hbf&GhRi4>*m$uE1X2urvwKRJ5(oyE8QG zFYn{QPur-_bWVe&cfn`!VG+CTZX^?aCrR}5V<2HEQV6T_J_vSO!k{pomNv@mAE^qS z1R{W*otP$eVVK2j<@LSOYB9q@Fc~9s&+rnwYbQPfJg9f=!ngPLz@hNuJr==X+E7dnw+vbM>B90bLs|TmfAZ(z_>Ura3(tyH=T*#=1hy$c@UtU8#=-MZv?Z zpArRRWHZ5ZspP&93a3?=ne9#ko5@n=<1}UvRjjTRVJ5uJ=%%P$F}r9UXzxJu^h)uJ zZnPn(`8-20YF^jSGqkARo5xg0WNM;31)cOH0EOuWE$Wx>3gZ^Hx02~Xdn*Z1_jovi zY@gg9zkL?u_Xvah7EgfRz6#W_F2D~g1$nD1m|M_8zbRYYw0K?*{qif_8QT2* zN08rG3-TLjY%S&nb4z;Ymvf_X=yfMj^tumM?I*|$@|z+-erJuX-dtG2FbnA=!&aEl zZA~!L8mg8j8xWo~TELJV`Yqy-c*9mdg@WvQOQWav@Uq$92*2a2qp`YJ=GMH_tDkC$ ze&bjtCK|m!n?MHH@FL_`{g$$Z_Mmr>O}Z|!zKt_4EbIIDYOG$cU#KHJJH17Wr6Md` zo#4GXZ0eWaL<{DHT=Q79{xuZ5qJ2h3GI7;T3_PT$7tweKmgB~qia5i~k^ynf zXOG@t{vvdG+#mzG|j)Bq5zn7%R8C@s=vDoH$K3RxfX9kd2uC z7D>De-_~diUQypzCmUBRU%p&6%86ENN#zAuGOc80MV2^PRx&M1JX$stzsoKtnVBWZ zFPuCvOC;f>fh_CIsgp0vvL2cS9IFj4=4at7W(()V<7)!oD{!-_3Uig5fr-0KTuW1lSV_x3v1~q`@DYu4#)YWUzqBXTAZF>`8TxmM{+*zI%k}RV z{adJi17w7X;Z3-R!C0s_ivD!+fXJZ721E*UhF`?vHy{*#gH{KA^Q^D%8?rvZZ@%>& zehaLl_${>Fp!K%(YAas;uwG~bP3swYgchfXQ_nv`|0d{PdxR*H5@*;h` z0H<71e7rcHaBwmv#maG3CdJD1Z>j#hSpSybSK>@Dd}jj`6ZJ3EvcTA)U!3-jU!3HQ zUsLP&1_17R>EFKkm%bh#czn_s^)}8kqw}r^isP{Gn}pv5IQc9KCz#S1>mzZNXaFaz z7vmJO5}f6E9?s&t5T}$+$0?Yza01ahoG)6B(>)jC9PZ0;7I8aH*Sx~|k#!BuOS@5@ zR{j&5!F4;%+1iXV%eUerwQV?C{2`oP_886}eH`bR?Z!Fczro312T*&5a8fwVK*jms zFW^k}m#tTEF8J#>O@~fr{|CF9lV-k=wQ)9#ghuB7M2(07v>jSTd=S& zKmTz4qxoC%Rp=|^S{J%L)Hv$HypFu1d7JW9_nb%1*@FMF`g6zcu`(;VoyMI{U<^;b(6?d-d7z!#*9hdRW~s=dAb7T6Na^p{Ir(8@hIA z^N{01UN4?BWbTkjgHH`UcIL4&UoFf(v+~TmoIN>@GN`*L%GBHjPElt zX<;OMNx< zunt=ihb1N?yqEA&!k&b!32PJD5@siiPbltrqUTFJFYP%det+CC^B?n8%rp4%!RDCj zW7=Zo#!SR-p>MPA7W|LKnN1^c>eLJPzY-^FHR3d|G^KFP*le8YmX8zRGVzbY#c&?< z%Q$~;8O{qF@1)_J#A7&jaTm^YoMso}Y|R(OACiw^B+_V%LC;OF96H~R&b0!>q4Ngm z6s{Ax%i^Ovl!F(2n9~t4`380V2p!O@hz4p+CX{4R6s;=7UHWl4+9~b zh4|=ta}mCRp)qCxf>1QqU?DF_175DB{!F}Z+F!T4@{c3eP|a%!Q3{Pl+{{Q8PV?3B z!1JkhYz%L|6x=4Nvb0U@8VB?zn zjG-nbhOxB#&a-MMAUN?)-J^3ze2XELI21Mjp2N8&7)c9r0VB>9PALXYDzKAZTL>$a$`Yr6XR9yp!-tP~^h-k~kR?QV^9iON<=}oXl{l)aPb;GK=A- zaN=Ynb^=-|5<80XDXIV1(0KiEa;KJl_zRYx0B*&a$6&`GtY%yE&2Z@p;xK~Te8-usAssv!X_`%%DNN1X7e20ujn8C>amE|Hqq3C({Reduv9 zd<)ahHS~wygk0+>r#MH`TLqjIh;L^4NFTlsahhYo^h57qmO7n&IZE~_(;s2zhYliF zfO3lAntm2=b|5~Q=?_PIE805CEOxkw67EWk>&%|bx6w; z4_nvawCEQ^FPy^rGw}$%LK7o);he^x*h{A)ir)}F1k8S;(Km4p;UCqnqF}=SdkW_e zJ{|>22kdE_Ot>owhV_suT&Z-wH}poG0Nz393n~Nikgs9pXuz3=e^9@Of*t^Lao7Cv z5kME=gv29iyRN~3`1Z&#obP-+&Y_-*Gp_S+es&Db=6(z3eecE@;6X&m+o`R7srxAaVV<4kmM&FUC5i1HpJKK4Ai2gON`bKO!J& z@f(bHrl!>f$N>{PywK-jE+CI~!kY*PMhOKEuXq~G5XI{{;pG4VjS!&GY3f@D)L8K> zz+Q{MFiJ)7G{9&SFdpn-QH(jUxHy3F06K`IF8Um{vnU4Lz$OjNCb{vwBTlu|Uo1V4Qj zi{iyP$f9EZb|V3>QAT`sU;$2mAB&UU%W&HJB%JR)>i_wFEb>MFmw?KD|1Sfl?*7jQ z|LFe8xlY$9 zdIP@pKo}NgK!cl&80s33GmuN7hJJvFvq`>yvy&-)vAm4qG+$C))GgV7^sOVrBuYF< zOD4fl+fX>sJ7T5v#k~Lq=3+WuAG9u!mmpV@ywS4d&*e^wq!!)eDMKDNoaa)`DXCjzYv`Lkk z2GM#@e}BW{B=Qf6Z-@p0YGT+H^y_wN-~sYXR;uoN4>4dMt{< zEI?av%I$M%X9Nm6%e7CbUw5Tpjk8>53C_pehf{F%d}lbKC%8@<;J?B7xId4glceeF z3Da@y6ZAbb9*0~CCjqB&H#$wuQk=fK7ia7~qU$afXO&NN3US{1t2jgcA)HTtCB7sy z1t;t0*hx6s|2=#!-~hfsunFHaXvVh^#zWg=;X6tv@qLKb@U4j*_d}@FtvP=5ft82pRJ7frt7+JrG|ZQA-86-0M>{ z1hteG+X;eN3VzxN0?C3Oc7k9w$%m$)0NONWWOlYh9p`%%TC%2|ZuBtgVvQH9lM>KP zOi$wpXxZRO6Fhn&cZxRvS=b5hFd!r!f`=DO5jz2y)Cq5kCC-Na8``4rXw56cTGYj8 zz-C9mmO$bxz$R!IwX_hR9ry|`)E#&j*d)N-0xUZURt(r{fF(r12BSBk2ZUZ4g4##! zM5>vAF{Hgidtp|*t)W^Te6dFa)>$&JZpaG}+`t5Ub4LVL0GGyrg;4^TFiJ#VHgIPT zxi^A4VjV0s5kT)Ba#Iv8Fal$MJ7x$<=gHvz5NCvoz);}MjlwNNd;-@T$tv(QA~6I| z9v4(LAC16H^F*4S9q4NW_!faayZbSm*Zl;a(@m#z)4ANws^>Mu6ifIYvZVhZ{6ZY8 zM}bKx{##5Kd<1ZcqX!^J|H{Gp0FfFy205T#pb?>g zrdK3}b&Xm7JMb}1!Pf{)O_BwImgMrqfwI7NH6Ab$Xy}1(D)E(A1>9j-WckC_N;QP~ z#`?vh&;xfF2t7gHe2X&byOQ7c#SY-xI_&{X5#tMMWRD`1m^4!N6ubR0h?WkTm71F+ z_G(4q8;H`Wv%h6~VLaC2VJ{GTts-dpw9=BGj)O_MKH=B^ErEQ-GPnsn>MN|}bW7ok zd4X>wi2%)p5l*Nt`;@al%W%T}m^pUxI|X(iwVd)`J&M{q<3rpBm?J@u5CAX8IGA~* z0|H)p4M!4vj8q5NS6h~IgHJlEaT0qnzFV4#lhI>|G6Gp8umSLGXMEiOaoavdT24#k z;>%SNVfkc(qULvI4vc4vI%K3hDqM12w#1p#-wZ_SqnrbpGF383@fk@^eKLpZK*K$b zhRP93=G-)t^8p(z>wgqqBBfP^g1(!9FJ9$GJR|-MNJl{GcSOD4ONgVC8q#4T^EYFB zG!H_LB#c3r)BJOFpg1u7Q;$ z9%vL&u<#90ZeNTSQ+NLXT-g6HWw)|)AI(A<;bDH~K)AyGCw}P;wV3mvv1T~-7IsFc z{k!;MbDjex0#d%v6ptgmN7JydDmVS<0hIHB9Glv)zLc4`5XD<@z=|4PQvJZL_)zjmgBlC1NMI= zVl@)>^bPvb5?Q7XeWLkcv}AdG=o91?kP}?ahGrUc1ZjuB1@S?<5%wXzOUEJAphqp4 zwJmEKr*8%XA!`HT;d;*OCw|{usWZ_A6o7kzsArS-k_4bhN%z)y!u@ayR0p{&G72C3=o9unkZhP z-&}l2ms+q(kL-srL;)%9YWgvV7jw?zOn;~)`wi_k6i`Ue4|3Uf+GNq+T2Nn&H(KrKd3PFs12$nJqm5_4Nh5*VIjU z`d*3NK3C%&(>w|hXR8rkNHjdKuIxX$|7hlc`tOU-e|QuRfth4*m?LJAaIgEmndB&O z({q3~laPO1xUS)8{a-+sfG3PHdt^#n$A21cvQ))tLCSz${h)9JmnsrxqIp`BPs14vhOB4nj zLhxn+f`G>$^oc>o2GN)$4D<&bUXJELHi5dG%kw0c#|Q85Liny|W+YFGp|;f$8Lw-O zzt{ApB2ImPWFQD}ywZ{xyRh@2Ic8wo4{89`HXWCJH>2;1LFj)OMvGF83COWJgREte z5j}!JMhj8X!E4{2u#7i%U+06+`YA^1Jx!FdcOmX+J%WH<_FI-r8JfacFZ%^R5K?H& zbmn!l;bni&J+Ew(q7TZ2d{1d!&^3K#G8KXluNI7v@qNbQo}`&)LZ3p$((RkF7kk%I z-Pv9HW(PnMdJ_2L+Y$rcM*I%W&EBqTXw5#?_qpEi7}x8Ym znV3^3AoX{|qt6?Nd-KYEQ;y6GOJ-&aq&gxgVvJ1&yNu%C)8{M5@D+Y_dY|_IF(D#@ zjCl=~*ID>VV>fd^pFL=8^j+lNr)8Ld_)enC5aI!!TgKLmt$>h}*P4*AjQB9M{KnYEJ+4dnHkOa)isqd7ilJt6h;!6G7hukSI$LR z8XtBG8zE1pk)AOOn(Bnk@hg(2_ddkmWO+0s?Kx1!?1L+DvIng0eUPwve+k%L4U@gM z_kIYFV}LxMA>iK|tDLkAX=e0`-Uk3dNV}G4>zYby5QnvFJ@Ng=qwt{Z#ZzXR@WnjS zmgVp|WPvBBrB#}M`(KirDVq_`V_G{IC)={qvQyqm%Ld%!N`eeYDWt6^&jZLqv=BvH zrtD6Imf*lSph;!wTPfVWDTk4cK7gQeq#y3T2C@A*5XA1^mcA=}JK`9>2nK6w`W=XE z(!ry<26We?uF)7GbqUf;fINVO`?a%CU4xj!*FU>mz4V*{f6PgpX9tz3=cS0hrzu$2 z|InrGIoy(Gymki9%su-73*n5zjHP*{V5iRh(z%fPX&p2`CqG9j&8e?xKHG^;Y9Zo> zn1Y6+>;!ZjpfrL}o4p?CwGEI}fZVGgC{=1BYI$7>jb5TL+k})=h~c&}iva z6QvGE9t5O6N;Fb-AfCzjf36|V0D@76z;&I1c`D_rls!5wd!_V>N51!T@Gvk-rM!mn zX}PGCIYi_#)^({vUOuwqW3-Hp9z9{-ToTG3Tcf3Wm}H?9MC??S?qS3Q^6NH9!X80v zacr^Sm^1@UYlK*D29C6UhEqZu9UniP<6?h*0-odyd%}|PU{_-92c-u+o_#-Lo)2oC z8O#&j2=5A~&1gsh40o6vU`=Z(nF+Zm^2aKBFmkq;SGXc_Jg%TUL3 z?$@3l!OSlq zf0~xzK9V65JvLD?9SuoDugH8E?)gtNH`GApK}#kaO*pFKA`?BBLc&X&E5iLs=B~or zsTHF9k(tZDd8X!mkLHdVLEkX_M?=Wh1dS{(`x8{aF4jFEb4;{XDsv>T5Lg2VN8z6E z*%q=-I`nLp#CMxd@K`;~Cz*s1fXA09-`yljQXO>N36_N*NK4v=HN%_u)otJJ2p}7P zW$a%{zZU8H`jP!h6xvLH|H9CXmIpHq$wT z)eG@LD^ch(IEt4@{Di%K-PkgTuY)cE@bA<-&=!f_>~@FYk+{o}iM#Z;01xt5CSrC% zAfAvR5q3u62K;In60Zfsgf8V(TV3SGc+Bknxk<<=lHS&`Y|^rz7bd+-91sXXypC8h z=|Iu}+*6J0Ga+dQrRjjSP8)nXt=xCh;btfswLNQ`Z?z&2=S=1B%Yi- zhI`_HHlonmlO)`J`uRyJ&$DV+x4g0-Q@NIF15rw#veD=zNeP0x1dL%T3;&u|0>&=| zuLpy!S1OV40`>>HDN({+A>VDTj zKC%R#XI`gydE(E-}_@xkM>QI1sxLoirjgN}W z#@>}Fv1ncDpSb8HAnyJcGljp6y!<4 zKk*lMjz3%@8OyM@7Ktsy8wFG&F1+{?qvgt&2CH=%ehGIC$z|Vy-aXC)z^)^?>=pJ3 zK!$5R7M}6cWy*kF%g}#-BPUs<2r>hob!JRmEB0piy)5>6a9WRF!d>Piy;yNbAreA2bb)2&w;?rIvIL7YbahPy&}5hT7vT^hyRcq6}X&I1o= zALSM9X>FoVhf1YF6C&>llEgZIQSm8ksx2C}oFsw$^(Y`~nLfc#PWL%HA^BYD5?Hgk z9^5^E?ZH}iPihTg>Nat=MD6=}a#gZi#_M)kA9i6qx{Wc^XD#f=kzDA*F0@O`7!6yZ z< z9Wc6L=j&Vo5>QD#!Y}nFvIl6l^pv_=dn|0)6%4m%m(ibm6ziT7$*=0XEkr*V{VeSb zT#e)e!{|>&Z%g)ce2eDC`-aI|u$Fo>d42MFBVRJ+D+HN#NAfByPn1l~cWR@NiS}Gr zCL1XfnnKV$E6}%8xoq&Se0L&&HY;l}6UXvs^ zU77f$&byE}CGG^LI$W^=2W5gu->^iC-b7ltdNACd5cS-%2C(lsK*=)5h?(j0B{1HF1L?rZsE3v z*Jvsr^lp-won!DG;4P4!W|}e9Fe@E0pzQAZc*=9T+^%!~5HR7czyld~m;j8~fJy6w zJ0FlWlmkKI$rj*lNA4Efk(_qVp>CZ!575nk&XsdDRJv1Lj30LmU=!p74I{po!DK%D zYlv{?0yY;oIg-j4ZWkGAjg7>_Dc%W8z&o1((O=Nh^lw^+;B{IHi=_tET0U0Vx@6*2 zXx~@yOSFDKB_r)a&!kfTY^E-m);_|ULusuhT&{Jo-g3lx{9cOS!Jz5IN^Ale!g zm^nlPeo1b}%Y0h&nL?0a5`HONl8+K;xEBG?3gDORG59DviqLU*S0Gd85RQ*% zIk9oiArIybfq$f+#^ZL|U)rC5>IrHi{1cRVEHnk);gkrkYZ!4pgtSBY-$=d_u${o! ziGNC`;H_G}bZE|ltl=jQXyi_UP8bYnjr3C?$yAJJ%6SQ30&k8AF$UMU8U_ms)DPfa zz=kv&G|V1nV~hxlRD^IJN11Gda36<9Q6NYJuYR7?boF?}+cIfUv4eOYR)I&1MbEij ztF?YqFUQmN65#=z1GX2g=nGi8@S8K%#adQlO|N8GY5WNLOO2g_d(2b_HAvOv$2hVP zrm}RBW_+R|=gC>XE(CUAq;x3Pf3e1GGxwX)?Zk6+UW*888`djSIv<`dT!A@xM)VAd zo-Yy13^WB?OxbAmF*DF)k_xp&_2tb#=#?njNu*G_jK_7nH9mfoE}MvN1S}tU^6~GL z_P@*j0df&F%%)i9qJ=r8XH&I}*WpivwPF{W2Qw>HJTXUgzKP*-pcP_{XxIgja>VS> zv@PobqzF(p<C;TrPgB;tpl4Z<|d6Vz}u5bSjVI4*w|)YshikFcnAIhvtQ`5 zwp({#Zkb_?!>q|#D`p%x?m~*0H>v)F?*wRX0k=)~CoTk))^OkJh^^*eS?2?4Tm7tb z-$B64oI$wM9;9!CbC%8r4A6WN_fs&d(Y#4%)Vc!Cs_63i_QKOJ50%1Nt^_60sKPf@=e4W~=8Sy_-#B4rb0N^y zzFZx+xA?FU_hrd8O@Bx0%5n>@GsP}`?TrBGWGfL%sX3Dgzd z;4=A34Ht#lN7w}@)zda$+@gby3$kif>cCP#>q7J5SEsAlNHZZ?s)^`hH1-s%(AlVw zsQoFez4Nq8ww=rbIm zWN{BebBF88-6LLO$y%(ro#$qEE2wS7FJYgnWt#$uH<sKXS@#5iN{@pyA&O$L8)%l5_Itx+D9?U-_W(=CmQy8gl9N6K|sge2mQPoz7oyF zeiRT24@C2j@Ybl+@P$(;yYhf`u$wiHb2Jb1WP3K}CJ6C>j<+Y;6LC*clydOwaBVLL zXbO~L-S_oHI}J1v>;%neIMI=Z5Kfu^$|C@ia<|+8$Z_URc;GKzhn4s;{;3Zb2-ZLH z0R3x-kh_4j3;D^0MGhTc#R#;Zx|&O_uv08G!q zGD~IwVrE|h6B4x`M{peb|qRFI!KuzQ=+A^Vs%~J1`b%2@!kZzzr7IS zV+_WCXImYGE%XNcYgx`D`2^-NaR?gy~EK_NL#C~**;!FeSI5htpb0?R06v#gimi`3Ro5qSy3H!SG)yrCrW8bLB0;MoMMsU z;7KHjXNRcnbDjJsoC$!Dz2%_yNc&$=DVXm$<*-hn_9E*#R!dBC>quavAy}{$AQk3k zDvMWI(|)vjDnOUg4iyf%d=cPn|?3$w_un zoKz>x$#Kqf20KHX0;doMTNFFrV5RT+l+Wjj@%8Y<`r>@?zMj4WUm~oJbl;i2A)q%9 zZ`ZvC5253@j)G$#23okU)6Y4>@jC%0=;S#^;1l^${YQPJzE&sIH|mu7R&}WFe3no6 zdiipEgQKLvsRek8{Z9KXdy9Ryz16-SrzJYL%>=p4kI zYoc0=+CsObB8~VG=>YtfAb7QodK0~I+71GsG?vbTPvs>&7QMC=+WPcn9q1lNaUO7J z#H>W&l7Ce2(=zM?Kk!zjVtUIqo^vp z^GP}Jrax0MA9CuQh3Y}|kfQy2ujX=q`?P)7{=NN-{jB|*{k(m| z{)7F3)6+?Cj=_r91_>P_A@vL^7M{@kR=o2h?6ZU@I(Q4%eh}|vK5Rc?|J;7me$3u( z|H9tk2-pJua2^L0`*bRLT$wV@w1(Lkc8VP@J8){iaruUPK^}zedqi%L>*X4pAkZx5 z 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 KFA{y29RClYLlNZw literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Bold.woff2 b/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..756df39b7c2163cd082c3e4ad5233850076d1e9e GIT binary patch literal 69640 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 I|6eeJYd87pTL1t6 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Light.ttf b/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Light.ttf new file mode 100644 index 0000000000000000000000000000000000000000..87ff0124b15f44e7ce0cad6db92f6d9b221a9442 GIT binary patch literal 188708 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

X+Nb9fuE+H_U_+nx^~fA1apaaCi5vP^djtF9E4 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%0DKV0-$(S4kq9X(pKbm7WUp9@zz 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 Wodv!^_+3g)u1&z`|EiU89RL6q%&dd} literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Medium.ttf b/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7a9c38e0461037ab2b10ee3e491833477b685e46 GIT binary patch literal 188492 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%0ASBWL9j0=@H2=MO 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

c(L?m5h!0_7CcACyA)8E7Q|?TgKo1$57C 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 TeB_H_lesgzzS*eNZZiE3mu~}& literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-SemiBold.woff2 b/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-SemiBold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..0ba50b9373a557e8e74f962ce50c07ea0bdbd69f GIT binary patch literal 71276 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

    +srs5YF>P3EldaW{)<*Ow*hc2ON?iR$#1 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%0DVA&hy5*L;M(0PMDz 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 z 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

    KpIxBKw(Z1{x8Qa(+F=^)>gwgou6q79*P*No z8$0NQ+ATzcMY}~0ZmHJvizv#!k2%dN%3Gf7x#CIu#!r_xiUxvjS0XOihwm!c$R z7Bc{!!h8fv(@V7M)e@0vZzm-!tj%AVBsN-B&kv|C5&s+NuFLDU!_`q!>ss5E6I4Du zZgcj#Xf^E1XAfZ6Tr}y*@6^3ZQR;+isW-;*&0#oe{c^YhJlQbaeuAKC7ebIb`B*!~ z+>Ds1X5Dx`r9dcVq@180{AY4=ykpzYGFlrP$;?dNxt+Jm-n>iny8YYb#v!6t9CEgf z>&lm`Y|8!pn;gpLV7od-OQ`V)0Hhr}**5La$#`c#O{1hA*$vf+mF4Hb)6VPw-KusGEpYV@(43`ef zM*FSq7XIjD|003(1_5>OKvByK5oba9gdKzWEx-Djmaq7*4O4FKA2(Oog$thVg5P3N zO2b}qBJGib7YHsJNUFCc7zOsPg=K0g{Oq)GK21JJrrrGI7CCBIewH!?{w8 zB4G9En=1GZbHVL-Prohzcsr3B)_2b<9St^m5P0{}OSU!1rDkJZ`$-IRr zn{A3VWwWJvM+$6lA@Q2Lo0>ein>~2S-kU}!-Az(9|J@8Y6-&&!${2BCh&s8O6+va` z{&so{@kv#~r>b`QtkEaydh6~vnKT;*f2TvAngM|fIksCqe!%|YpL8CZk&;MFCdB+w zi}S=7Ek3Y3`!6fbnsx*iAK%!ppfNwQ_fn|bdNcFKT)V-aCAD*xF5bcBWq#N}WO^dU zqcusn?-VLd|hg$mAW>gH4bb&vWQAeO*&cb#;Cr%x13UUo}QkV?rG12<;YLFc@o*!AHuiKj@~ zlF3%eypsIrqKXdN*z(h0QKKD)lrR_YL(5tAl@z|TFZuOrabjvVj%xASJW_8UZH=%_ zm85Q@Xx3rdxbMVmTKhH7M|Dh#mP<~|%Qv$P=-XgPrx+Kp$n40tz{8YZ+e^M_Xyb{G zko^@Yk<}?al9n;-y}f?@qPHYvOC5!PHc{d>^3$nc4VpILBlV(pC+WjCbVN-4l$y*3 zoEnXR*{llv_QU(Iw7xjC9h4uuVbN~euyb|X;=?I&>g5c8IkM-M?!L4P?NM|;j4Z+~ zz%wZ{bzzyTpC%G<>k-2Ec@`LFo|T|aFP5dgB2Q{`!2=i#yd`_9`~OKd=5>ap{Et-m*C^U_3g3 zR)BmGiBvOJs@u15=6R6luG;f#vhm|~0xjQtb*BrTbmP|i!%m>m!IIp#7uOTSYm^gC zVB=Ujh?HR(bX>Z>QoLu_c2e?c^q67b6J;S;b7g8v0_tRB+e_cTVFCGY@rl3wB<5CQ zRZO(H#yb{}xVo79@*c4NlVAM3v=KpUA*&k@YXIgYbr$iZ@^a3>k8*1}x=n}M!KxRF z6f37W%M{i|Ug;5PNx>P(j1Kn1ToSsn zT|$ZhfK5>ucgpa?PZn(aAe=B`WW!0aQ5JH5GK0ekUU3o`PkoX>lBU#Ui7vPlP?&b(z}h@EDWy=DxfpsI)vpu z4v5Oxt7S|*#6Cv-%fp`AT~GWQxI>yMMq2HJi?WT@S5`kkRN2OI1lPBl<-yJjjA{mz zqLM2!3r%0RJebL#@Y9US#TGJLd&UkV*!Xjcg*=2}YaAQA*dKg#7ehe2O5-E_c|LI! zd^K$y=7B9f4MTPP@{bpt_lz)1h?Wn#2fux*y4IfgudlI}4gmuZKYSGxvf6rA;ld0A z10DHIz4U%dDQe_*WXf-=rCSQ1jB2m@&>{;@wqj#W`@XnDp`%5sNjxmz{ukR*qbL5? z6OiR>n&z%~jrn*r<(eM!On~lXPnGmaB6+J%3Xg!5SbEbK6dqA4%);9-C!hX)?7iXt z;KC595@YU7_A~jkVJ#Hho=4>>n2~ay7NC1=QHQhnp)$8U-~%pzuSNsD>qn&Xs50g} zE!q4qNCc$a;<}Xc!$%65x02{>-Q)ZC;i|LN?ZLfe=X@S4ww3VOYLnTDEUtlMP8gL`+NTlSMy7ciO12Y{y&4&3Dh7 zTI(F_Q<5KaZ(!UlKmmH7*=0ZmhRr^}^81`(FZQZ9C97$ncHI{`ndR$lSS!%5f!ud% z3rXPVpi}sZ`lqC7gD*XeS*^>AFww1EQYB6?a}cDK5NGn;~E(9^)|w zL^zpF$tMhMdEq~(YEM67h=?G?9doJffhR zOWwBP`_P9*sTtnH_wqb3=QJ&bi&$~o;`+>z!~~p4tga8+22O{Cr`lG zwTnSS;VGMOI&N3dp0DZlIn>=H(UzQX+T^uxLha0So^QwdUp1a-Yp++L9%91JO>f|4 zAz)=$0Pv1r6?e~3+d8ULoVT?T^IOBX_iXecw2pFYi}EtMf}*5sUVo_t&PDW7@KzWF z7RIAdo0xxShUuZ7{*sZ9H|8o|4E(?uL4id;t>b zlG8iCp!*FymX2hzkksD{@hu80kYE3RG7pX2`%dr6f+f-RK+Jo^`$90Qn^)fun7Mo=ePMVD2zVCIz$#s!yjXW%7yw2N8E;FiTCyDhb|N;#6Z9w zlP5CCY=)R&$eUP?=o1ku<=TbItaPz_)U(0!Azy5*c_hDZ5bzDUWf*USBc?x}5+!pf z2~oh6uX@V6 zpNI9b&hH(08pOkpgWtVCfj(2ok(fsSK&2NoK{Zfpoov+Q z5KoZ#Eo_QN%AlKs6pjmML{R;h?D};Rc&!#>>-pEEz=5nbh{=<|6ZsLtAKS1RBXX7k zz7SA-Y6qD4KYW}<*qfQzxvFz@X5RWagpYr)I>5|3i3VSSooO-UtRd-bZw&Ryrc8K5eM z%r-^sf1K>GFm9lea^^R`K>@{EyxgqJw1z1f!C`INw_i#G_mRlI@goF69f1IRPUL&E zs^(B>sujx@wZA>g63_?6pPw(rV z$F%=#&LEl%cz~COY`Jp9mw^HVz(ZvX0wCq7sZJx>lgDhVO_bSG&DR*v$_9e5 zs<{fkP3Xq@Hg7t z)(ttpTnhVU{-@7}wqC^SyF$A%FSZJn3eyI)$PQ^y6ae0en6;ptoL0&20kP1g88 zDW7UbKiSc6-B3-qnCshch~tOS5J-RLmWA_l<#~aU)H-M4Jo%oAN@d@pke{%rRMkCT zQX7e^&n~n6?ETD5q<*H9i>7>ETvZZ~fkv!iRO+`0iZioy5!a7gyTWL$Uuf;_o}Xu` zGb&h)pBC#xvvUfPtL%e^DgQA^WX69K%6|+piTNLyMEU3^5s|mI*pxFri-^1#1joF2 z(kMd~b*0Pcqdb3(I&RU+Y9rnuWjH({Ds?EUb9AzJUdiL5P8qmF(n8AF$70mSACbu) z!9V!`=KTCe^AlT#GS3e{O)BK^EVH2Pg}*H$=6!x5dbdm`3M|v3FnPnSZu881yti=Z z`^#ZSj`q;#I7A^o7kq-E+I;XDUVVmlLJWzz3SLQ`zS3Gd_{V;5YHIG5*M9S#frtXx ze%xS=uG|Vl*p+|gG=Vp{lnle&$W@33mIlpC2dM@R$e$ zi$G9B2f-cF1~2eRm-bWAcWCSp;*x6Xu zIGijHYo$=(=Gynish|r4{{=w{B9GE~Bj-6ZIM-!y@o%viDdjH@sH`__T$B0ko08Nk z|K_e_upha&mKY98rP1g#Ei6V0Ge!S|8XRdHbfsv6d1D|O(PyM4MDq7l_hNv z*mbup>~{S1pbb0%$34IN*He(T!zuCZ#~VM?X$e;;7pK_{M4wR}1x9bTvrmmo&B=A& z`F8K$-}}TXyf3vZ|Ekt>TYxk3ZL3GgNzSR_lB1lX;gVU^Nnq|jg_4FW>$`QqBx>O> zi(J-uvW7s1sHlJ+K_gTc$B8$w>`6N9V+!WeBl%PB@ev^9%;P_j^7HWQg5`MRX)?|2 zYBSWM3Y!c2{cJz0-S?ZC_}eHR%Un#!lHS1AG^cMl>EVLhUjA z(0F-@H*0|_<@y2df+KcP$USj?ertcRe(@iEk_;ozPTiA(>u`9*8(hZI<@=g=5;aRF zs)WNuBl2i@xAgRUI$!d*!ug#jM&5OaCQQ6L(t@IGPW-Iy5l*7-T)pScv~B8@{$4MY z)%|X3`a_*eTK@y^)+F*0vNy5b(@Zo$oZGz+J|EJzkS^(?(Hhc9kC2^dFbKVc!D*5{`oca4pYMfiw}-figY}*Pk{d!I(3~_UKoT_xfiV^24HS3Lpzh(h z=)1T86U$qkwhuZ$JB`Xl&SJQWO*HoH9etCMi~5=pXHf`lu#E5Kjz zA!%INz?sbu?vM-QcGkNFgzK*2o&D`tUj)=J0?2JuRVO46id!ywFe0`kPE`$hkORUg z#GWkkxl<1mkg%ux>1bxTZZFL+=%6%~CrbsoA8LU9v4x59QVe9UPZ%i44wV8c$S%~A zS(S7D%H7+;@$t31TI}aPl^1KOan-7(dSov#*q%>c-iMy?Rp`dlNF+UGtTMw zOdoM|K1dC1HRv`#r()1X12f|^SSaGg3t+cg%4y(pK;S|0H5T(W;eWUq`b)-ZX7pWl z3E}~$!q@_UMi3o^-yHxSK|yZ@GiU?nQZ%Inyl?GGL58BfXk>9t0$2?M&Szd) zU%%_(FPlKI@>+%8i+?5HjzVqz@l(80<>f~ow0oD|P@me;hfV|fb}c*p&$LbO04&xJ zi*eBn)Yh%ct?S>cuc%fGrP~RaXo!5a%P*7)LWXUfGdfM6w70q@-0PRV^E(o~LV$ki zGPe@MXD-D{Lg;BeeeF@qfDnn6UU9vY{GDVGPnR9-G{l0<`s`A*>mLEfVQ4Bp1*F=QZp9B7g zLO)exsx%lXO=d$yrNOiTz2bc+I%$zP<@Xb1XMP>mp_OEyo?^}Tc_00j?kP)aw$=W$LA(U+Xm0iNf%i87Ftn{cei9?y2P6zZ7Mp2)F!)h2@&D0~1z`6gKp@TrrjBHIu% znGEp?UC=>~Mk7I1+O$ZP@p=Rp5`DBODrz*%!k#c!^uR%KRCA7UX@%LurIC1!9uA59Q!;S z)w+D!1zJDl7FE#_n6KZlxC<(JFopvksemX8qJ?~F*B`$H5KTbo`t~NyLzDl7>-)c; zd_3FHQ&H*Znx9=#nso41Rycazqs4alHv!eERn zW56(=NYp9j5J9)+8)7(WLXQ?78EzrE@0~ud+_;2YAAzzI+C0CYuE**@8$AzT0E?Qj zlubb6mqOyB3%6RDoFm-2d}DP!140{T&zTl6C3Evef~zD<(R6~RrrGUXu+yxuW+_%Fs;R*s4Z8rJ5mcwm_aEy#}~=;jqrVOeGe%TUY8 zTDa2Ea1^Uf3;OFPRne>{#t7b4+EqL1*c8_bFWt1F*_cI2Ezjq%^B=1O410bRZu;r9 z#Ow61tjOBXoc9b|DG8%)&%pYrjYkQ9UB%UQ1z;f0YCZF5e5mY_$nJ=CQD}7ZOsMMj z-0uz5-{6*t5feY#bWAQ=fw^>&O**xjJeaW?Cb~{LB?I@Mx%KaG5Dl zwZimlyjFJ7Aqy&;fSk{*CI;o@mk>aq`~K4dr;3xrIKKBWHNr~DL)0K{6GhLm^PFF z862(}8KGLh{J^`itZk!%f=pfvM=Dw%yG6jw8-Jv#KfnQ*?6dah4ksn#PY%xi8 z$tKrn}r84$KdGLO?7-B(YHI;XT*pdbc#DL4?^*ReFr5m5id(N^UMjmsd$;-3SO3v(a zzSa(XEA03|xCEHJ40&pGjX#o@uO`Pfs6NIvmQpbD3HD&Nq?7L?KwyFEBX@!O(-kE1@HHZuqcwX;LM~?ypZJWwMs5Ru)1YXj<(FtQA-ZXu z;rpWmbi4=zgmcd5wm&H&=s&lmjXDtof&(QuP_5AQZPK9t^tz=?nqy;yWirsCo?e-j zEGKJx`SNiWOQq^nxmfcjH{Z#UZ6`rbd>?wMK5E*=%+YD zAnIbJ4HK#YyU}$YVvCQ^zJQ8qif83y@o)jd7VUCW6PaOetdw69xqUgcrMGx8LYh#Y%4^bec@;DT}j7mE&TzM+fXh}~uH^w_y zIZTPm<|=1vHxD-*;5!$^6-tj9u>#LSZbMmr)9HVc5!XutQ=_z2O#fAQVM zfG=Ku8R*sl9DLcAxf=TX(O*lzVvo>i@;K~K8m*X4>Lf^sdnEJ)0_fvTOu+^PkI{s6pS(VvgOm}@1511|6OuSG-sdXWg79OU!{SF;yh4)j zPYLUqL?CZ}%`u31fWdsGP*;lj9CUe;i30r9i<%VDb7G*=6Gr6W&)*O~%24bl%CQU~ zO@8Kn=Y~BFd_jje{lg|(qtg2{($^E34I|SCN6uZ|#bD#FveJkw-1P8d1(Silsstm; zb@p2iw;WajCj%sS1^*KpUwlu=e}_+U5DWx@2uE-}ZZm+_mrLe^tpYI7pz(%)rgEPyJkq|B_zFq~^@?a^SkaB|blDybpp0vdk=(9HuDPzz^9L^) zoIlRy?l265cYxce7`{L&et=R*Dug<`pHHH|DOz=%;AJH9C`t=AIwrV=VjjZ)-%qG< zym*{x`(_vjbknzS8wbjt2#nzkBThJld;$HsBkGW*2B`mZprdDPj{iWp#-hNT&8lHW z1*SI*%$#OSEn@Gakm0euxo5zd#%#dz=`bm0QAy8{lbcRnzN712(@>JE#~H%57MHcJ=_Uz2%mCOu>I$ zNAZE5B#XXs%~r9P_8l32xoaA78!Gy8AQTYK3t;#7C^NlOuUjJb5hb|^tvxMbI}V7S$6U{yI0wz=Zd^0Hx8(k-xFXzj6Emx z;>sLlj!!e~Y7WX}rLYerfHa^K_JYh6e2K2Jb#=TPr++1hu&566kBs%W(xObaxY2WYicHJiF#k+H*L;nF=q^UuGVVzh5@E$Npbnu^{o%pRkBx*ns zGpYKY6xpbnWNsl@F(?bMF(>-8)3sTWumPL+zG5NT%gE-11cAye#$Irf#O+xU=2wnS zq82HvM!PIAKLMMvj4JlRRQHo=yjV$frMALH<*SeuHJ(ZAKT#521Bt&3NYvH9MNc10 zsxfV_q}&W_^4)6O2b_bkjo(Dg9O6`C;UfMRgLuPN*IueMoign_?`XQs1k~2JeKx5k z2(P9Z(&R~K2^M6Lj9C3VCkLD&)5f`GKh(j7{)V`2Z6YZ0Dk#+lsqu6W$j>Q&^ZKpw! zJg=KY9%r^cqZ+Ta8s*qR40p{h(Po5(TdPEgT9b_#s_WIJD)68ax_%*W4W$d&>QI{G zuM;JACXz8X$r=&3qGbcLU_dCfh4VB!?Om+2vKs19ndHqJIk)D8OdY7Y;+y;6T2qYU zs7dnIBgvaZId?i^-eB79ER?K~fh}4djYqZ?iG$9J$G|a&bY90DY`S)Nbn1N{@ z+H}p(;s~uvlb!iI!m9sWZJZPx7{K7Dq^ZkfPjZ4d*dL=q!Ok`k$*4&TYNpfOqCQd$c=WVN*iboGp@8|qnIakiz$ny6EuG@_g zO&0sn9O0=agY&v1%bV53F#J5{@!?%&kd=R-j|KPdQGB}Mj2Pp*@Wh>M z&fTl(%;x0&jQVLxAH>D%WbQo@ugOi@VU}Cgw|d1eZy6|ua+s# zL@ZN2{p(07S^uy;Hi{d2Z({ev@%ulKqL{hYLPFGv`x_{VZvEBDtgm=7>!V*P7dnOi zBju>&F#zQy9VhNo{cK^lh4b|OrazZ6xp%p7x!QmHn;%^~mWjXCl{NTr|K;VmT@FtR zu#jP_Mu;2s1Zm@r9{+p<@ye=PXa|QO`>Iqu=#IX7b^(me8k5T_ljB|*WdoBWUW{O? z%6npnq}<@7R50hJsv<*y`SBn?{lV;vyM_AUniu2!GM%e~?65GbB4b@f*BG6s@0O}` znr9c~KD8&c19dde#JHLHts#d1+?atJ>M(~p!jX=0v}0z+UQAhCXS2a!4tInj9pz}p z)a8L=XIZLjQ4SKa#sR>0Z2r1Yk`B+=;Lcd_s%WJnayE)7*Z+uBI5@{h#|)+nIpuC= zd6vJYdNfbh<-T#U`w#IR+-n)pufe^tsRp=35Ohq>D0M3@9tKoOrXMUhdm%LA^|L6pbSwTy;`aY^B>(u$1<$63c^;Jx%zZzS zel*+!ZWrM8?|C^Zi_6dRr9brt{3#;fUD9CmxBdeH%EHdeq-&n=sUn7Nl9vwvwfOfx zwSM{l&=ui3&wty4MP`=yfDEX#jo{ zfJHk}nCC~GHGev@sF>L^cZ z*$SD|vN0rnX8WzNjUObPF(h0XuxSoL9+D}sqaNv1mLa2D7@D$6CfHF+{$MTXK|Dw! zpe02RNOe1c*u@zL;|vVqVxNJ*0HkuMq4-e=AhUY~L9S7L4EfT}{{7J;Jc~MJ$^9-* zstdMT0n&pCL7fOP9jzoI*zoH+MiN2scetZuN;2}4yley&z{gZuMdxGRB3KjS*dO%yC5o5fQcwd21>3k5DumL(wLfr2t3=X5s~S57mvXwqi%f zk<({jO91Y7Q>6L`BLrmqUg2l!Z@p#iPg?*yFhgV~23MUwN);RIu3);|zPa|`w)B-nK}qHrS#7)HLp?ja zyH~%)faY9z%CmHo_v|9xBm4*=CLTW? zSS^?bf-zv6@}7k>;2t1ov6qQyUbC<_NN&xDZ76V;w0^D(oQd|vT4RrG85tZE>%iJ* z{08y-%ZFV-om+B8LpYqjag-Tc2Z)003owGjbQ6QH$NTO`=rt#caFFDgP zH9Sb(piWfsu=>rg_o5yCdFf!05(JwY8rOF!Kj|Mzk*tmOeesa5!S1IHg{&*6+4 z6W0de?HFL%qs?Tn&Mg~{{?MqM;1aK|MA_@D@F#M7nybz{^NH!wy`=0XDo-^yRHxx0j!#6Rqe9!Na_+eops(inT z4e-PL-^a6Qol5D9+onTpnQXeTW7Kfw!JkI`NZg+e?9PTiD$?6mJ%2L>)T1Nl$v@Gx z?n6v$*x0yi9@!<$@Zg_0w4Y2!<>M`!@xH}}b9Nr>3Esv1@Up1tJ;Gg@$7e-SRFpv& zj>ZE0XRy87?3l;DQQ_PO&RH#2S-VlV&e=ie7EH{lptRNfR7*Fmto6aSnc@2{~wR{UO0db1^^Hs*PR5=?>h($tAc=E zgVm9H-o$=~*Dmq{*zcG>WOkaE&h4FLfq?(GsLzBg*Ym5w9!1cwla8oLAQ;NtQoGPV zM+z4+2YFEN9CK-z$cY!?myHh$^ulo-98#!ncNDv4gT3Ot5nP_sE$O`Izej?wffDq&?iEVwSVVLCxn!!ybvYjUdS3tE6Py zNXj^JuljrBRO{=<$|O|iXD;eS+s4{dvPnobUT(t|2yQf2a(}tGSh5WvV|R}gAB-Q@ zwI+pP-6p7}g?khU3+Ya@gjm8z?g8g=jrGsyPp`nvonWpj`L&L$^!3XZR=tc2`7yUz zhnzep}>onm$ za8X-ko~hrd{R^TR6D~cRFU<9AoP|~A`veoKon6AU=w-ORr{D@Dh=GzTvFHWcq_;@C zCGARo``2rp*xV_kE%Rj%SzMX)gC$mu%+ft9SIOL~?!KDAD#I8nr1U4G9uZr#_}lzFRY$x zWjl9{-=N}d$FITjku&=vFlRpb3ZFPH{IDx!QcI8~!SBh51~2VANymaafLIW3NqZ^S zerZW_Wl3A+%Yd{%*3!QgiHg+Y!fKJeFlf!_(TBNMNPS5DqFya&(XZ#|&A{W^HWtjqALUmb4$kq#{Q#~Q!Acb>Sbt9z9_31f<42;oQ>R!XsL`hep z$}z5v7qS?MZ9B)qHGnmW^$TaY!sZZa7m43~wGnpn9So+9ZZ|4m3_Wxn+!4?PsvI9V zE?IoUzPDt%u4p*)jcb3g$6->rH~9rqWLL?4F+t6oW)hUfmUw)ugl!gwJ*J>#k2yP< zWGg1-2`Pt}i>?+8J+>%I*kzTxzQFnb<%)KC z$yoce9OUC3DMd2XbB^jTeV}}<{`TUdU*6;a{uIX|oZ~?Xy@aV2TAn{Boh&OKUWYW2 zJ{3K}T`Zl~eDA5EHjV+I_R(q9K^>Q~&qFP9CUnr>4-$VeFO~url>!~&Q;+CZ;^fo= zRrg3zcViyk*BsCV|Bi3j%T^8_3X&8HXOhdpB~$|Ye}=jHe0kX z+mB+@kfitOto{q~*35mj47;fK{^%^A^@)1*Y1zL0267US)}Rtq8IVUUw1k?}<6YWN z-aYMxRHmvS-T8>$8pQ~aeS_|x5nFUs6fYl4!alXS(Y^+>>qFYU07GVT^cYfyx=K_{ zCl0VRVF&Dvy^%o$F0!afH)2!1G`Q!P5I5{uHX%*0d7J{+MyrBW97bRa3vQnBjgZRu z4G7Lhfd*i8X(Ut$!+7f8RQVr3MRJ9%p{a?0EJYh`KXW<1s#QS#&Qc8aLEvrBGV*z zUl0JJ@KYd2THD>b0O@DRrVs%Px`jl5;un$t6DN&a$A-{534h#T00*q*wJwlAQX>u$ zQ;41q$3QwjjE49IlejF!43zo}ojOsFoC9T%b~=d&5m`SJKVtNp>SU~DwQ3QDl5wnx zrNk=05ULA(Q(KZ^1$`jp1RH>J-VlQcJ_0RJW@gA}J@h z9fzY~#CK|tk{rb+khdZszf}Tl4Bk+F%iqjII zB!|+t+xntb`J4LRjAC;OyH$Ex2Vm_8{yhmr$>7*sAoFFoN|5l{|LrS$%aJ5Iy7a|B zSYt#xZ9aq~2qeszb7AA+4`Odpm`tomr!iKVV|cz&{s3+L&)1KC#_WIC(sh{9jbJb; zQfCAR0a3c_i3pUbSh8a4NDvvQdKU^|fG;K-qJS|sqXJARDXNpbF`9I3sjI;ER|PYfAF z9z~RllWESsdXp73lW3xij;VX;yD#2@H!FyjHpR@0d2(Q8{~}|-(uXYdWyLB5=3B*H zLN<~lOKf#)rAkqs9S4q<1K1(^IB@bl$3Q?JJ*Nm{%F01~fM)Z?G^^-~V z6QujeCHyI%{E3kML}`D@iGQ0}y^*IV%BtBy|KZ^Oz(fQf7{dU9X(&L5I6$aKKp0p+ zIA}lwct9kGz!L?fOe#+xT2~+jUm!WoK&;+CZ0567((-OQbTnLa9<~v^u?8aymYA^(gw^R4*|GR6`?U z6H_x9-Q0pST-Qrmc!-oA%Rc?BVvgZ#c-Ki;nSFIaDtFDwb|P}13I@mE73$3 zLrm*-Kko>(n>-KDgJGh#E&lZo5yZFg{tEndgO*MAKzfAqH!6mnWxlw8>-#=Bh)Z>|WHcARb;BoX|-x zldY>`zW@Bb!iqw>gq6mx{OrRU+33bLzKKnaP5T7j9&^pN&|*t1x6*2B2xf4M@Ug*a zDOMsH{N_Bv<2~ewc3kI%PXsE>l>R}+dBxu$3Q%hOrVH zn7!!ZXbeWaNh9~D0~k3!y4y_)YYI}pfY-;C$FjwCY1)7$n0m!hUe*_;G%dkAxqN<` z==omif<i|i^7+h3!5)IJTtlepMLnZ+NDjW6>X~0A`H4wSh+52 z@ht}1htTwPUD}m6b0>Fop4dfScHu_a1iP9qfI}f=hwoWGP~TqP8gAo*MZuoSP7ydo z-6Qt-P~$w1FVvv!Wu$2Mrw}WX5+T~Ko+nmf%$Th%Dtt|3vLyF_y884{g;0SN)mDC| zEwGP(39B3?ej}QTq->@2wJi`2S9!e2<3c=d_oRiJ0UQtnr2~|cdKqvA*yWsVz`fe!^yjEIoUA26?JPPe{ zotbv7^%y{~be(_*6GmBe5n-aNx&e`scwVvE-CzJjh3QB{ocFY-ZiJeQy1c9`4w2L` zQ!vu#=*U9ZLx3RaO~?`vK{*rMr|#O&-N&xeIqhX+A||=e-M4J?NnN;Fhbam!)5ru2 zBRaY1i(U73_FQTk84y!0O&e1#ZHTGVCv!4FT=Mr!iq=iOTBs`z1{cedOuUX37|tEx zRG>mP9G}AqPPT5)%I@Z1d2)(3c;!>qM53L`PIWG)hNcR%j(Wvv?(9 zWc0F2AjoA>5QGXtQ{fHTjNRqI3L7l(g#mURJ(KMlv@&j0 zLR2VP7N#S?NcQo?rh3JI>}fcPh-*@4rF=|8Wkf`#NMIdM^L=!cWyfV}3X0BXiH&b1 zW^{!j6>^7z*Y#M?Y>Ked<4EXl5W!lj-D=->Cu5`-(tG8nm z-&kZj|JmdEaaN39zw?Z=4AR)Ex8nX{Rm$gADKAOVG;zHuX-96JEuDPiHwzzC5x&+s zaWfuYGl^QH%N%@iOMQ4BuitsMH+$zBi{IHCk^OmA%;LKR%w_&5vQu4Kjz4!Y=G~oj z4Ccb%=ktW)ig?xFk%lli`p@h1`JElx+9Vvt^TaeY_=jC&zaYmK{qtG;$mct9&5!*L+=#=dsM<3! zG?zCt6yQ(x>7{Z1DBVdoRK&OJ^Jq@Yp4QReDKT#`C&e{wAb#}KV)pZi;8~K zo3Oa3>>)u`kVAwpCWJOI?Mjb&&e~SJ8dAL6IzM>1-Kk1$%axW_ofAKPYRU}?bVI4SuH2$Z2PI0mQ&ldM zDEFKoa^MDt041^o0C*Fi0#IN}n|&fG(<@hDQ=Rcz&a~fZDJRx5 zK9!0?UIoCT4xW3ysblmeg;H-Vw98A`kEB$tWqs|>_w5T{D}xVzt?#=-acbHaMpKIB zVQWsWEJBe2>$7upb6*uFfJLdp7jYxg5{UG3U}<^Or+JD`6nsq6FSVe758 z_ie(jK>q71>}Y`hzKt~fNduo<=Ko3a++zm+Qe9&rGZdpII3&9kza$A$gT*TQ&{cbX z1!Ujxv8R$jLygGL>-@fbU-tgyar3&VtI|wwg7r7ki>M9LD!VFFyty>{(F?rJK0hvQ zo;RM+t6HkMVQKU*OU&b@G$`x%~aA(4&&aM=ve<#J4{E_by4e^?xf7tpET3 D?1wsG literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-BlackItalic.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-BlackItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..308529cba2bc9dde32adce0556432cd206fffe54 GIT binary patch literal 206964 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

    qJD-NU6z>;0|0afe4+B3UgJ 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 z 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 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Bold.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1a9693d97fe25e8635691463d9d51a63ecd32aa0 GIT binary patch literal 208320 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�v)g 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

    W$?`|>FrI~k0Onu-~^9q?^ST^$9#{m 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 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-BoldItalic.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-BoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..abf760439be83f7dfbc2661468c05049aca03f12 GIT binary patch literal 207204 zcmdqKcbpZ)*7v)rx@S)y3W$h0Y=$TxPTT|$VUmCdiX@SP3@~H{oEefLA}S&(A|hr) zMa+l^6;UxEDkA2D2^150j2IZ$_gmGqXBy<3=Xu}z&;8ulpI_IiRjXI6%2nM}J)%UU zJ{Mo)V zKKuS{AC`)!57095jDbA|e)aKdb?{%0zsKk)CDZio{r8EaEdkxfl~hbKu@T+~H)Y)9 z*<;nDw;PK}zgcwJ%i~K+#2OsPnuR))?PZj8ggx{nsIHej^)~3b>NzeIIa`bB(CSEbGe?cF6O#GVY9kYUCH%obv4&(6gI2t)eT%%sN1;Sp;mES zt?uG_uez7({b~)@wdx_RkEj>9zN}v5`i5>xPPfzKzAZUT$^9i-|LtXo^0K{b>QXCe zjz`UzMqLy+MvXFc(xNRn6M56jn zN2f?j{f?tkLv$^P=@pJ&TRQ8pj;^CJRH38mN=(&t^pVsAr<0~yTXqM0Won1hPrI%y zn;qYirn1J-zNAwlY#LQkOJ~eeRbvEIiA*Iyc3Dy2n@sGhj9qs_= zaZpA}x%7oQPR66BMsHMl<1ayC0`dGamIK2Nj_bhCaLfmWgyX2O;y{@p*qX3!05*@p zH|YTDjOCT&dWCeAiziq+qVP<-J>_)V5_ny4|L<}r zaaWM5Gl^p+_Kmk?U~I1>uT1`ow&^b?Y&7{dr8>3)?;A(hRPx{0n~*#n4ME;l(DRzI z4fGnzP5zpcgkz{F|KqCbb+`^4oTu5ulp~q^P9SDevc`tV*nAeej?%@2|BDups9Di! z%?H-Qu&#cTaX(tc38DKAZBe2%9;mA(wgT*#CbP-SL>-SxHnwFkDg`yclx~fDR8B*7 zs!SxOMw6Z>B|RN?JUmmIqSCfH{}b(DoU0oqg*7=JE{~d0I36vDoH&-AhQS(`KE09Y zfvoGNwPRA2jwhL3@OW}@t}0O%sHG~dkJ6p=2K}=B#PhurueR5~YwP8Co&BbM3%@I~ zhqIYiO!BAuxA=GZ_xTU`Px;ULTl^3G&-`!wzmkqgYL&Dh>6xVGlU`2xF6p;O?Z{D) zW|6Lu!I24(b0Tvi3nJG?Zi}pn+!J{)vOcmU@>lvL=_}HIjW&uljiyI4qOGHu(XP?L z=(OnU=-lXK(Z$hwqxVPGL?4Yl8GX8WUwt981-h15M*xqh?yYKC}w{Y(%d(Yf^{@%;?UcL9)y|?a-SNTWncY$E%$ZUcM`K!p+quigDce- z@~28SvH7z}f8dE1@zThj*5pqoU;Lx|mi`IMu15J2{c?YaztX?gU*oUyH~O#nZ}{8& z9sZ9=O_N$CttEe+BY(Cf{o?Ycd89{VWMtwY^5>`YdF0P8(T33`(W9eLn?GG_{!~WK zkIsu;S)D&mROinb&ChcAbJzj-Glu+8d)w{pxVJO;(_?SJ-r~JO_MS)nT($Qa@@HR_ zSCv{-uc~2HR#jfriB$zv{j0`QjjNhcRarH=>Y}OzRg0>wth%~tS=HWsb@m;x@7R6a zP5yXCl1KdM-sZZ0o_b!bHI(^NeN-oAM%1=_%$)c2u+0B@*?;xEPtdZ^2<^Lc-|T%e z3{}M{fU+#vJ9_WMwnQ)6yLj)?s{SHhydbi3rIEp%yYq{kH|{)s=Mnr0ckJ8QVQ251 z1v`7~WVN$1cgH(Bp4;)%j*K1YJ8JLnzo_EgonQR=#dlwP`o)GXR)~ChS|mBev=2%C z$XtWJ$T`N1-0QrCzAdsc@I_eK)ci$;5;iPyW`YByR62RkRXy(&l25a|xj~pW*IVc< z@s=edy(NS`4|e+*)S=dX2j=Ie`2+l+)TOchcz=#RpZc`gzu(;9V+%Fw)8KA@ds1E2 zVh5~15_*%e3F&H()IBLb!TqP3)Zq|3v*N4%OA1ybl2kW|6j6s;C$&w=PKueBlgM48 zKdCUOIH{Mp#kfg*aQh?;NE((jGHFcGSbV@-ljbEYNLp!V?`rQ(?_KYH??=DB_o?@u z_msE6yU+W}yUlyZTj@RE-R|Ati?`2Vx1A$QAtvQE~^)6D%} zWaj_Ad?+8ur_BAoliy{J?3F5|yr;ddyl4C*Z>hK1+wJ}4{owuK?eaeN&+)!cY2KTD z#CzD=;h*Py>3iN~-Xg!!ujhT{-Q&;k7OGm_Ti#5sl5)S>u0wrheo3rkYRO^JOpauB zcnl-OarD2Ltka6+RAwKiFjDmO_A*9HV!WHcC^1_G$(OP~=F7#b&MsjcbGckCx5^E2 zv)m#N$piABtd(n7zig8&vX%An8(x*XE&rD94B zH|8imGfM7e%>0$vz)#FIeqjv#Q_hwBavr0ZmU+sT3zR2cF+ab8xzsx{Qg$-te(TSo zcb@H^@1M&kHo!lFHP0~rEZW-Xw7E0=f&LJ6gleKrQuXP(VyX-6_XL%z@>Dm~OdX?+ zRhg^=>#z>2rw(TYc%*8oj#5W6nzo~-J5F^_9o6wFhm~L!D?nC%YMdIcCa}hv#tN@e zO;Q}J7OBOo^sZoq$Lda%s|t0an#5RhwOXdGRm;^?YKgi|ovUW4 zi`C_-hq_7iR5z=9bqlM?73wfGSv6E;s*#$i3e~NuNUc=G>Na(Z|Tz<$1U2r|wbxSudWZ?qdylzZ#&(xa^|TtTo?%5ig%R>uRjM|svFbT>idyaW z@cZe%^?pW5&1@p#rFylPQPlP7Gio;S8hb~0M|w@YqrG&mnb+KF;k9HeZR@r3GFg+} z;N8eb@|t>C4^Xe@Vd@3-w(h4sR-dVz>U;HX^{e__{h|I+`?S(YI#t)vhv~!hk$RLq zMt9Jex|{By3w0lTnjWYJo987w0pWQGPeEelSqaZk+WM`%?Ou+T>n&%6+|F;MUT0qZ zH*>H*m_hv|bCh^*c-y?!yw|<0-WKm`?;G!4?|1JPzqa?cuYINW>MFfY$35kFUXqv0 zY@m);&pXU(=pF7I z>k>Uu|EBlo>3XKVOkb{->Sg)^{gFOTf2zOIU+Z7>@A?m2t}AqBKcLQ8iD5?6rz%}$CaZ3D8 zD|b`;FP*>=?l(BiVPMD|D%$IYf7>DOhBVQeN#}n@M1Lg_Bf}WqOy7wfgU!-LKf?WC zERXNkhr*NaD|q5~zVx@Qq2HBu{{z}qhd(A`y)H83VCaYATlHNs{2y2t|5k@lF7@^Q z0^T)@=|D4Q)2B+U5NcP`Gtl)fX{5ivoe55prvD?(kR#L+-jhb?*^o z=&r9Y{ef3o`ulaT|C#tcuNLWfPYS$`5(b zn%efXoObn<6e3ed9JX(=>BPS3{_?%}+cqCwA}(Qa6!4>zcHY4#L`)wrtzv zBfQLCx{#;y6RDG-Hs;+L|DN)wUtJeWoft-4GngL#hUc=$*c7q# zcn0*$_%F8Ywj`ei#(y;Mno2!eS4!y5?vjRHcS-g}8(DBXbSLh=j4~M?|Hc~+&(!0A z(hwY0-9Bl5q^W^7jqt(oD(J&>mK^4t8GlcY#-@I9qW7?~bsG0CNA7)WxI-dd3iQpu z^f4z0W2ofn3$bMZ?SQ_(v|XFdA#!Y@-?IHukPm79$OF@6O`I-$)+KE=9kfl;PIM#b zsyfL~)kV&*?upjTRxPDH{u2~W4{=k~iIjCGNl_{w)WE ze{KEitMC7sy47Cq06)if>ra63e|V7p;P9}&2l;m%aITsV-==N{2f6;Q(l+TBY3EJA z=HBt$2m6y!Z9W=m zgft!k9(BQQM!p~Hy0Y*RWfCe6?|SYr?eicvoZq&*Oqqc&pZ+Mg_aIlF%RE1f?)1q( z?Tqg?&>iJeiv^4wKxKfz@xQHmD`Wqyw$HDx7g7&_YAW5;NXCnHGSH$0gCrdBQn-JZL`fSir2ATPp#r5&8wLx1s)4`9TMEPBZ)sz}aOztFbtkZ!tzoU8|cE|N{$CxE_skYuTY^>7#FF9KTQsjGVrXG3h$m>viP!b&QGEu{gd? zjs#7?3`h6FJyy*WPvuH&HHJQ66nQi~{)-wxo{x<0Rh^j=kBjeP&Q%M!e#i~sJ$ffK zN_wd2aw7W@iU=!4ZWQmBdqEGDXZP>-hDf$I2wWna7@M;hV|sYQa4*HZNQ%6F@qTq? z{4cGXXI_3hM{So5dMJp2-@qsFuhiF+Wls?2NtKHe z9Y?4Ou;(7;Dfh%*QFG&;gALfy4O@;>%b0gBW4wF`yIvyf>iCbWAKs#@?gj&lom#N< zZz)v2N?+9&w?1`gigW}`)LGIIG*K_`l=5d8ML(Sf(kZh%kgnc~U(38K=AB9!cF7Th zb!V-V;vFk(4fMq_McqhQrcf4jBuRZDIa*W4u9Ob`3zEdx*HI5)E>lWfTEV*YFzVM; zw3|)wFG&CCjH8OV=RW2{$1``%XI$%G^9q}2)46&uvW*z4I&(kmTl?rrVytXV9LSH(Z@ilwc88@B(8 z^~a^O<-zD~MEsqk1-hDP-j$*6WZjqNxxzC);R&e7dEf#tAMg~L{1;&#m8ElWA8;6f zI|i8DHpR|0wBeg4@dgKn8Nb2l4(7fD9d;+e=ec_P2~f&Ai6_Cs;8FbS;fkN&kb|3r zY$Mz)pe3|<-!>kaFgeD7C+9r#4g6n)_)Vdk027WZGfIhn?084wk}vU%;Fch~T3Ti#jlZpFvOq%@EL z%$te3cxS?UqeuyFUC6WK>43K?$#;UM0q=d1e_(4{5+I!^dEgt7RP0D4?lj^~BknZf zP9vVQ7e#7OA8O43>(~;4eC<=gXfPXG1&FgYx@*5JQirfQgw?^$I=h8UQ=kG|2HphN zT@SnK9RZF9PqN+aB=7)u348*67dfmBxRH%pM*+&b!6^W}4bB7C0QT%PcmaF}{t#(c z4^Xcfr32pn93BIYf!6_bSAy+pza=>3N8nCfTzIQ;Crgx*By!d z+w3B66L20MUH)sY1COXi>_b*pq;j#2d)?Ca5#7Yd@OQY0XQFA z1MUIOf_DLF?dSpOV#j9yWqh^tc(*h6F4Vs+agnYMgIB>0krQZR-DqRo(gC)gcoNto(tSR-5v&zCDHHSpBf%`N1W=z& zqCTBOed@6k+zTj+o<{)6peO0?N&0(!4Tv*;3P5i@Y01a7g1VqJ;NAl6E#TgQk3_5UdjKH*NOBx8Bh+rNJDSz=sgtN2A&k@(*P_GreJ{d_B{cd0!D-L*h^X{ z(k~gz1XlrM`nLr=z=PmffSvt66FDsgioswo7W_b0o&=CN9hm{>9YDUHL4KS8Zy@eK zY#r1BkdDDE!FoX64k;HI+5`~SP~sYT8ra1ULY%|80LtPl%6>RyJp5&me-ZbHV@1wR z0gs4`oFGzCAKWK03jQeE(WHCyc|Qr;d=M&;yJ1-dJ+tzxxEWjoLV{3S9y z6=47LpG9Vj2ET~R#GOf6XAJ<)iOj~GP1~CNyU4lA7~=B)_5QrGz$B45jR9qLKK{9_ zz{5-d&J~%L308?*cpcM$N|B4A;B}FUD?~1#PF`|_$O6*7fO5XH8R!Jw7g;zPkPi#V zzlEgfGVH!=0=Q6Q(GqaC$mOSkQb0d(`L*By@RGjB3CUES<)Ho6uEkZ$kLX8IG64fxn>}k3@!%Li)+>b z%JUk^>6$$v%W4DUmvsZkE<<)1vdeA;kAf}WOHd_pZ6nY@Wcf&u>z)E{gYQMIC% zjBo4+$p0J3lNe|gsK_=)0R*Bq_4q~7mpgr9}nXXtWa_cgYm6YFY zwLlAS0yqOuZnvK#az_{NgUBl6SD|+md9i8}_*CRh>fdVOTm7cUUBf^*AaCxv9jq6* z`y7#b&~eYVBKIx;r14(L{@z!?4)C|geGNc6Kz+M!D3}Hof)yh7Q+^M$2d^+S83J~R zJb0VPTH;zuTx*GIEpe@VLgXQAdw8kHBS(S7B99&mJ_N-5=wBj_Ve`6sL>@=y6KP_-2O<3;}cy~xj``xp9>-wqS`oiy%wQRL4ok-y$yU(em_^dUdvt=Zvm276{6 z6y^00<;O)u*sYy1R8;CfQE3;5s>LplIuk|JeO*-jvqc?tg{TJKh-x%LRAY8tAMvuN zBNvHkx>(dv+9s^PTP>Lxjf#@6fJV0j9Mp1*=y*=a?QD>g;x+Mw0H5j-p1j7d4uA#$<|OTv21M7BxOa)CBTt;ya=yy(?-; zvZ%5lqNcKI{2cb;m+ul)@q?)8EkwjYOS)lc)>&f_>@sEg2b(fNRUxtKUEUIJbNUx>OS7oh)= zXTkfT7EA?~f)7PqS^-G!rJF=8q#PEKKMT2UA?d%2G+&0kMU>IyQ9xW*3^D)@`ha}8wk23EYB}|2Ic0Sna@Qeu9qGC5Z;tE0zn=2E;R;bVa?g$T ziMok2-E^y{n+d!5D^a(QmKF8E1)^>}44`ji9>DI~D#4qgZeJ?u4$AzFSHX5b{i2&z zs~P}oSQP`*fmP(ys>xt3SORVbp6U#Y`z1i%2GYD?CfFtFY3zFjd!M-mkk8Ma2{wzO`%@cB!Rw-)%K^my z+?}GHpD5~uOUZh^Uge{wn1y=*|_~jc!ZAR}a=ZbpuZ1AF}*GS)%k43!> zy%l|1UlH|&53uzOY~40j)SHycTXjUe-CNW<*!d21?cHZZy?2+W_o)*f5Z{NC!-wR- zN7(yunW*jU!Ox;TQ2_rZGirO(q)Xt88I%y((vsfQQsd2ZUm%d_bFh9s2^~D*e&YE7exI#58T6} zgd|V`ZU&U)&y>&4w3(m(E$WvAqJE{kf4vqw4Zaff+feW-K;LiFjo%vp%Ki5~U=)}S zt{1h3I=80-pq%!+41N{$M$?gl-#V}fya#rP z+TRXL26Mm_fUtNi&lFBlPvg^(-=s7Sdt55CUH!8FG^(~A_p8@?(jhd%Z z>>g(BiZ(4t5|Ly{kyQ3b)@6rcefCH;ki(_19KkcJBki-bLrd5BKa#Hfe61^&35U$~2X4uetWx za?Ioj;}nNZr%q9g$4)3KQT4}`myA}C31t&F`$%Ak{LQ(~$?}`M{%Eh?*z1ldrDG<@ z_Oj_y%H_SOoh#Fxt!bN`SKa%WwN1SLfKeZS22B5g{-ZZKCMFTtu!*L&MhsU z%05z)OUx0uGK1tAq>5P}G;?3B=1;N5)Lf6@s(Bts-M|;rjSNdO7l*^_m1`|~t!=MS zdu`6ub9Kc?utMQ_I9JUM*4DTY!jo(bGj)sykJWzTW0SE9HTSVr;XYF<+a7jw{Ybs^ zy0hxGt+Tbxsyf5!w5zqJ*5~|I)mmO_VXZ#3I@i**blUc`b!kh|=A?~DJ36gy>bBH1 zsaK>9PR&eNn$j$_b2=E3eZ)XQ!KiyLOt+sLg?+W&e4prS%JKi^Z$)4Kl z*#X^`6g8qHrSL9W>$CJ8u0weDq4gkQ?m(VI$!8?=FZ33F+tYw&@t)pD{S4<%{VQ~l z{{0Yl?6!COM95kC-}a90?HxbZJASlxBx3*8N_}mmzOo?)#=g_)q8CFKeGReiu)4m4 zF5(@CvDf1rrb)@?R_aqD1#gDsePMZ@1w5DH?UwhE;pq>!qQQmGLlV!&HiTX-6!N|e zdC!KtdqBuLHsoy^LNCcZNz~SKdZh-u9eLH-zs<^QwKAKn{agMa`I?n{(@MT!C10_U zum3}Gqm|rbC113X&sfRl{~`IDm3-MszGNkzwURIVLvo#!++ZcwTggYQq}knhV2U2M zl22R7r>x{-R`SVzNUpV#4_nDKR`OmedH+8oAF`5Cid6^9f*QkY7(_$-gg_XI~ zYFcC^6M1!s4Zp~SUuZ)PwC4h=h0&apUTmf2S}pUSi}ZYZM?x3lJW?~Q)N~tipsot5 zi&+9vv#eCP)l~^y#9mL6HpW6d%~A=iWmaY?yx#g8C(}Z`soqlWs`uCh{SlMRPt_M{ zhx$tGQa`94)z9h|&Y#gGYF{UFGQO6st)u#Qovm|pcYTsB)+g(sdbs{qO@B!n40==F z%jU+q_!L(&h6a4B;N77)X&&zLreNDvc0ysfo&>!`PvH8h9>;YvJHfPi@t`}-hqqPF zv3E>{-l8XReN~U=x>=9m%8Z;)?8FUX*Yc4}R4=N{>Q%KxZKbb%haKSC)#vI<_JHqJ zKdIl;9`z@^c$M0(wT|dCT~{~IjdfF+BBr z4eWK_X!pKvV$b`lb_e`6ySIKjd+R^9yX(KTd+-0OE;%#zFf)KeEi$tQ<^_jH>A|ND zg7h7jx;{agLbW!AwiL#Z)`@Y%d|yDGRw-QXQ%PKJSINYAJ3JHj?VMGjX5%Jo(wq=# z<*oJBd5?QfcrSP_dM|mKyqCSr-uvDM-iO{t-uHe3zoFmAKiqHZAK^FgkL29u7{8SB zWaBtdHi0vWll;m46!YZ=pO!1Nya&ApnMOV2JwzLN#AAHmJl00>y*Isg*xULEC$Q>r zHfz7s^L;-_4!7T$ID*qNXUWlgL*i`7sIiXsz_q=B-XL$VH^dw2o#_qp&hmzP|MFh( zUagTL^|hJ*^zlyd`g*5&{k;C(Y2NAH0CNrui!>Vkg+=C`v{0L79cbrEzV{t@^P0C3 zzmoirUU~qPrfM0$Wqr)~unRfk6`@2mqqjYa&pfGS4tf-{M(QVgx4?VSV?IGyS*vZynR#u{ax^n}&AyE%Y;FaqNrThU_S;%woWKjpCy_Q@r#lW$ z30y81PN2`M6Ou!|#^^O=8fZ3i=wJk3zQAfAg8u{%TzQ!f#j^r;6{!Q2xHrNbrUsa^ zX4RvIYQWyA6!tl6;hf;z>?XQc%4H<2)|9Bv?sx6C!Jb@7zAd%?XyUBzcY&MjcjKDp zcjB7qcjcPncjlVqpTITOKap!IVyi6?D;e`U!fER`MkeMT%e9T;7!5JMeTZXXiTTHK zP26Sl$NY97854WV?-1e``D`0kUU(L3Q_|f^X4+VCtez}uL#|D$vDoxlwfIhmIXQLE zc`EEo_siq|)ecSG-^Y(vO{V@^&Dv^CwwmkM_FP70$T>(9mUUCZk*5%Mc z=rbqNi!Fj4Ob3XMa}3%{kV{Fcul@I#7KLne*XdT^C2^~bFTRr z&PH!EV=LqPTi)B=JB;vud4GF*y(&&z?>A#SrGC0SAv=)zGlUbeXWEmp=6g{*%eA%0 zSiqh;%8zm1YPx+kgT_a1F z|Cnbs`#7~cMn#whwUKXaFVa>@?TEfvURAZ_HFE}+v&ik_Pfp_2SBG&9!+e#g1O31j zb-27PTjg(ggA=-(=4F2<=XBY9d6XQ_S>0net=mj?2w&+?QPo^!$XL|^JGZHpoI@Tb zZ>v_SwOp;*h&fxG!#V0)c4)Tc>~A}E$F}Dw%U;g;9;Z4|7mnvVaF%qIcT_fKugA-K zoc%SYg=4A{r_;Nt&cO*{Mxt)=z3L`UsT0|q+g)~XLZnb8s2(zjr?(S1)0;14oNHdG z3OFNOEc?k|bE3D1bJE{&qSwq}rg5sb7cHwo^_Fuu)q4sj#{0-$ob5eT^yX^yNI^x{@=}<{b3ZoQuB3or}KCo|nFn^UybQ7J3C|pI373 z`F8VNEY3UgT`W#J-@{4g`#9zN0B4*ZG+)NzWb-4OYJQ9p&5v`M`AJSPKgB8Lr#Zp= ztlG%A<>y)1yr^DMn^@m$W`*-AYn&~ta<(%2-)7gZZ?ldwYuNW$&6#!V$E@khTJ|$m zc4j@hll7fh(|*k=?_19Le$QIZtZ)C#iqEWZe`VeGJ1f6GSo{6O>TfUWzkO=IUHdB5 zfoA=i#A?v2fm2x%nssm;R)+O-ea<*H&<%AXPC7T%NAN9@BUvjRrH|&!bGmNEYPmV< z#umCIYpm9~jc%)tWv$ho)fQ)ISV?EHnl!8FT-KB^&L4MXW!aSz$lX|9niX~rR+;&_ zKo_#sG^_1itT_9y=IpCaWqsD4724^n(avC%Hi$LN5LV-7vRXUKtjSrkovlae5z^C>)6XV=X|AJ?9MtbWlg(`^Ulllb*%qx;B50v`euC#tH4|JN=`E0uJ2$i zcqiwb@6vbcdsq?P$C~f~R)r6;E_{fU;UlaKA7gd+IP1eFIV1fP-@AF5RpPU(6Q5(H z_yXsoU(%cS2F_+y!mqLx-ok2lE2pBj={NOT`fdG=epkPz-)9y1A!oEd*4yUhmdF=pXgJ^-ua|{R?Nge`6iJhx6Qj>c2Q2ADklJ z&pC48B)R4+xzB0x2cz}Mg7J{I6OE+iol{f3fN?ZqBzA57E@OFA%@w+b-=SDbHq>P4Ou-&ct z{FFdml$YdDzV5M39+!LMUU^2IWzLtz_n(gPkLJ|TYCoO#E2+$d7VssKMSNT1A~~Bc zbIh0L{bqjDZ_X;|X-VcwHZAy;O)I~(Tw+!XvYgdKUA{{46RW`}Um$7DdzNcu8Q&ne zi*JRkVotMEZf4zaqujtZN3QqVv&P@VmvD~rJNm~b)*JGq`+`F!zq8+k?@^t=Tapv) z_Z)g0;_H@u{8RYC<*9x@zH(VJml<@xY-TvKV&*gcNWX-y?fjSZgMSX+4XNM@FVp=Q z{!G3iGMg`moX59$&iCgA^B;e{f02K&e~G`qzmzvPm+`fk?NY#3XFih;SXX|`8`=+f zCitm*?l1B$_pk7;jPx8;UOJ;Rx#yIU(dARil6y`aH?^#EQgY9tlF`#EOKTO3o=`q| z`joMgOJ}7OjG0jtzI=Ux_6&Q@4&v^PE+qdQ>1t0gvnz{YZ)b(xji#;GP7#+ zskt#wo)e4owW)~owU#+_wT(SoR$xa$nJ^=#<*~CYN1Q89Xi70i*m(y^`(_ohbNah zb)~NG$JM9_N+LTaZCtguKi(An_!^nW1glt2n3z1lX`0{)e}YYakaIbmf=UnzD#64W z1wkY^ooY`SS6*6LHo2s1%!JXA$u>=q$u*gul~dqP#*Ro?kleBo^I75Ysnf=nM#@5B zxiPPl%%2*R)6@gXX=-3$t*N2f!CP)xP^3JhBCk`VB8a5oAUm_Ox+G1WS~ia6ZR$p4 z%}v=^`H|^CoYN18bGplw>8@@}w{>HBP&Z}<(afxgCUs_Y-Iy8FjoCGUk=a4rIM?2m zc5ZdCcw^5Vn*`3DV6T&Hrsig4IycL?+0M-g+)U?oadO46fZxT*b;)(|2{+H(=j1aJ zdfk0lot(UFLYcW)U7UQOj+4)EcILSIa$L>GOVn@|UhGP!OM>r8G{?o0+H#O_T@UeauaqX^tsVe*C_=>GGqeyRT<(UtXex_smb7UR}c-bx;j=G32`# z@?8uC&e8&BX@Se3LKkD9i?PsITIlo?Iz5HX!a}E~$jKKu`64G@xVnwyB>R3@nqq^E-HhWcj%_zq2RkvG6;4f*u^dvnS}u@VorV zclqP$e=H|)pG#NJ<0J3#E9mKpi-Pun>*6m+#P8By;PezE{E7I3@+~TG@dxb-J&E)s z_%8lnWFg$eAM}L9MZrje>*9CqGUm!BKj>MC^JA_&V=ljYW(AeBXI7~C;;E^=cue&T z8j$mZ8&Is+Rr6x2A*kj-$Ba2H*};H^-z7Wfu<^U(1p^^|m+YRd+IJ4BOMcKiiu2tR zEY>r@x7iHeb`Q8V`I)g`06?G1wjx`7@F%h@kS_`b+~T5Oz{PdN77P^lo&CW8jNjSs zs!M*N*#rX&;VwNzt{N4&^aN8Wnpwg=R}I{N9t)--^fER+?040|4fL^KASx~j27Fvs z%&vQk1yeWfcky?2@h6&zt5*5NuK0^x{uR4s77VQDwf5o`nDRD$Tc|;Kn;zA&Y>#RR z8lTM&T$iArf5z_&3HojPv3iqBrkq_expeH15|$Mu<%f?d9bY)La&l=!#o6Vh<4ekI zOh<>fWm8!~ut+FF+6FcW1sYAKmQ1RcUQXyS|0$rlN){Ky0*eYVjBM zRSGf_a>WhNdiLzn@x4l>oLf>dYU+&Al5%6h!Mso;u3i^(jx{POP=;Sg#D`>|Bom}Q;1@*h2Q+}h$ z@&AnF$U`w}qA3hkT*ZaK?4Y@3T5ola+GS+LL~ytt9+9}kY@$U`wh(YWbDftzg?1jBG~ftxlI zbcr>=?t`_46vSMA6bq_RLCp1Et}z$Hg5j^gHRgg?mtzjdh=WyU{MXRxh%@utd@tY4 ztMjwn!0lG_dBHlYINz=8^V~cz->vZTf_Wg}!Nexd%@6b4N~Y&f|XDks}v$;Q4NapBGH%2oEMgd2XVY?^gPGZhe^NCTjUX zRYZ?XXJ($8xaGT*e_oMWez_+AdG3ixUNCVh&Ua4&^4x?j-#rP)bL-7KH=)aSPXh9S z2_5&j^tp*%zI#HD7pzN*^Ii9v@77oOZXK2H);v{I%H>dw$%aGE@yFVv&FUj53X&dxVAdr z+G>kys{^jB4%wN(BrY@4J7^8BSSt!`#ZaCQZ zng5ngm^#M1wd2jun2zRP9S0(hIyAeZImKr(m;@Bo8b6zNAZ3_sWXs}|OA{>WoSj@6&#B8p_Vm(t!D=K**RarX5 zradbwmRu4T=NC<<3ox}iGkBoOv!RoR)rLmc?7wgeAtvS|kPzHIlvKQlisb=u_V z6*kRjQzn!-vd)z0lPf1on>;%xhcOdoOc+xd2$h~Qy=1Z_>y%Bctnt+^nKrF_>Z}?@ zy%OF%1#i#-E%x2g=&4gijh;<@(-j4Dpw_$y3f6IHkfTZ`Po2qYI>?|xvAm;uz-tz` z6V9Dl#y_%5to!~E;O=I9LU(BH88dZenPWDnW=@~x6eQ0Kmc2p7yY?A#4~%1ZwtZ*D z^78EaKm0rcC=SsDA-X6;=hx7A*^bUbPi76BYfBA%?pZ{xYs1xiTg^>;fo<-gek?C5 zc!ZjlW$x{m!!Wu&thWH7~3_oE#bhS0m)hV|<9AR!^;$ETTxd(lD`N6=L=X$O@ z_dqW%sEe6-`L>SX1_NWBd!U!+UeV;ao-fb6s>yQ?^zwoSe3^Offp%U&F!1NNmr*&H zol@<~LsM;1?fXMR*__GA401asv!Ek~gdHzP2R!Ew?8(XOnQGr%hVBl^I48^9;a<1p zxYutv?zLNvd%2S1UZUjWbhZ!Ju+Uaw=jmiUb*pU+ywwJWMf1a+?69XG?1_avJ*}s1 zbrQm1xgk$>_%0r{n{F+zFgq~U=1O*c!QrMm>6kyDXTd2&13S(rDepPCGBc}*>tFs6 z&}cSY^}*6+%d6QZo5r_Dw+CnCWrR5^FQ=Ka^3ubcm6uF+R^FUDFlWWhzG`!_yvA?N zNQC`-)imU1cXi0;vGdmWBa=!wpFPxG``T-vy>^~bQa(vKPMI`i61!~8K3%gT$n5(z zC!@_dYo8rN$+*UH?dX7K_MIofO&oQuUw_@iD;r!szi30xh28${wxa8TdW-bK>Ko2N zMC?fpa~4FYh3tP(DndL>*(JV_ed3R@)Aw$6EZv+f>=$3cKB9}+Gd_#Gt&`op@qzqL zpkAEn>BdfHrIvW5X!^#xfa_I!%U#K{c4zjd?A%uJm$|B=Ed9E@uC>>T`JyfV!_}L~ z^tl(;a-vfwLAdPA7EtySvi@zTI`7%ATSr?9__#CBM%9Gdh14{5R;%pW=Q1-U3^| zCa@8#2Zr}3;EPM0F9vhLEKm+6gRx*F7zPG{e!!e|_`m%h!ilmpbz(Vtoy}fkcJ5Pu z+$nPQ%_*53Kb-3nzJIDD+tQokOQAQ#^SMSiHIirdT9x@z&36Dgw{+mk0G$mQ0BU0A zh;xmf>SoaCZ(QSdyiPa5TLyBi`@jDm$4Mx&r-f?YUF&Y~Ydu3cme*q2Q?2y0->Tj8 zv~6jt)8?m*NGncjo4P-BSL)W(b*U>-7o=9E4o@vi`z^IYYSUDm@@2}Vlt)u;Pg#;O zH)U+fz?4`@dP?o&zmva7elPi%8^0a=w()y{ z-)eq~`OV=skzZf-$hCD>pM8g0+3UE9J(Tk}88Mu*3)x=OOJR@dTkL&Z!#>(Y?9Uy^ zzTZst6W3;+@(%VtKg|E5TF8H`8pCdK&M5_F7TaIZW>K4q+stj-nwEEt$yNRj7ANi0 zSK6Ejpys7gzHKSIRLU04NGQHmmO_c8^7S(~_{_%_+7`m?YB_vaER_;Qr=;|-9DFI; z;Y4xy?ir`xj?f=*ui<|q(xwV`hvhfbF9!T1N5IFHRO%Jq5|d-8H%`NE zaDIei&LSvwQzMx&4I0bZ(56zx7|E0oT)Dr^&3ub?spX*ESkPt>GCiP`cSF24UrYHY z;3scIapG?MH=M>2wB1iK>r z2ZG+U4gl>%iEkbP3NwS_!Cl! zFQ1!JP`jzmd^Ow3kOp&itKncCwE6aqjkVRNfLjwwHAnFU4iigU&m+{teKWFAVv9iA zyk+#0R^(9=ILhbC;KbG3wqKX7q_$`t6P8aRp4J15yf-$uT6vSM zHDm>)mqaN#Ye{KKr2OHQW70)RTT(trY0%1lKy$_`kuHA&X*PKk$xA>7M&6k$rQrcoWa!cVT|5kgw&sy$6ed1|# zuHkzb_S&I3UFF0$5#Dzouy!Pz`HmY{+YjF~!Z!iswbp!xgISKPEiFubtO1%C56MTe z7#OZ*G_`fKg(>+(KzTDL1zX!qUy$(&JmQDrT13X@_(oceNjv$TL7rKzIlnBXJ!FuU zjICD2luHAA@8Fu8QQi~rnP^LgCgm9>&j_bA^@?{O^pE%wt|{i*Q6_$GBr=t_CNA5D zt0)91^^85XKJ(w1Bx4?)8J2@js^E-*Gskk!@0qxUXf- zgpaHV(+dH)j6Iq5dM5uf&gQ>~k?)dAi&x=WJsxTEOwK-GBsmRZB(Yhq6lwk_?u}M* zEZ30;tc7#G<&Zzd%H|v4uCpBS&$OTBx5L?BImVWuaBjvO07r3lBh;5Rp9Oz};d^bF zy^{*&jMh%Q3?^mKBBNRl=`r!OsBiT&;Vb-F?S~$T{@S=fKD)A3DMpI z4K~$CHScFM$dh^^IdE*;*m*Y`^qc;@d8P@4&l&7QTWdDlg)4O@vjyduoHY60CM46L zT4r%Po6syPlWt?D91^;0Jc|E8Wb7;^RCz((W?0EkYND%+26@QHXe&eOFf+7&Xp<*R z|1Y=F_LbJ=E>59QQiqVVxhg9(s~+`%kyIc22c6H@*az_+1eDroC4bc~98%{KR&pFI zLa8sUe9TSzY?(qzh;8 zdvX@N4y(%%(wuWEQ)zp?$uaX)jCLQinI{pxm0w%uwZWz~*u!;H8){!QJvcIb%jV&6YNnab%XZfVD4QaGA=}geAt3vdi5dBk#{;u_x ztv?O!ZT&%revA3Y7O<)H#@6dY^rInqO^E&=MBg2vsngYZXu;L=@({fwh~HdW)BChu zXMC-;g=oWn)$tAe zVu()2Kf^swI6V(T-|y(vHFO*5YBk@;taLIrhWN``EpD~2)%@0*TFq%SBScRN(Gx@T zm=HZ8L=O$o144A)5M3OidxYq&*pusQ>j>TU5OiPo3mrcL`e;Wt4$<{Pw2?`3GCqUy z{(x@zXNdkKMDMPlTN(LXfxNl4{5+sre$?`vL>+FqHAKU2x!K7)kNk#~>$t9Md2fhb z6{1&!=<7rD(hz+`h+Yt)=Y{BVL$ryv(%Dc3J>JoyLiF$uJvc;DPpaknKo`1uyF+)T z?ry@(4$&P#bn6fu4be?oHfmYd=}8IEx`u91RYSL)aTk*F)3anZFimLiF9(|G8yLi`(Jf?C9kodP#_06rwK<(Q{kOYEj-| zvbnoOm>!FNq~#84F)&2;`ww)l5I;Xeo4iWsiG^sB_5?pus{dNFgWodnwn&F=;%Jkf z3A#au4$IUI@gprH<8OCwh|c(}hM)1HNX9pTOva7`ov}URy%4=EM86uMUkuUD)X+v- zwazCJG&&y+(f0>&TG`d`R|fu!8$`W=zxTLasgZzhf9{{#Iz@*4t~7PRGRnl_uDn;V&R zPS0BCdmX(hM6U?Z*N12$ztqWJQIl8A7cei3IsUxn=QgiwUS@pF52nXE{wTtRHy_OP zwB~(6bYTr`?N7*bui=|IR()^h5S<;OJA~-gHFOKwY4fPD47Vw0mCmoTY9h$#3luP2z%m)&5bZmm+-VoiAx|H~fj!aO<3=7c%YiK+7 z*dO?#{c8BpUf5;8oHm+YL$|IC9dYvALh`Qe8%`_wqQqbHKjmRKf2fm*zi7LfJZafI zG`@%EaJpJ!bG4n}xJD*4l80qryz#dg6>V8VA5aICZLN~j(|@{hPp3VmyY`q)9Xlj{6*4RSALiZzI*KEU_wJq^jiian5=tn5 z$T>QIan4?6jMLhr1svAcUK?k;>$HwIhjq>oXRia!7<&!KATR=17)b~i2{2J0hLPs` z-P<#x5y9(y-+AY}Y5l89)z#HiH&orK>aL2GMf{H?`2Uyi2e|j{=)K~H>V+s!}97=e9(6g|tu#j^ONDNOabZfYi@C1KBdqHcrcEZS8 z!PbHe1#9==uPdl2SQ-tlEG!ec6>lZ}4+Y;8%;Ege9{zUj|JmFqW|22GYd|R#yPIwh=S4k@Q*AQT+lZfp6IVAD3P%y zEn|K`R)Ih2PbqNZhuNih2iTn7oZpE3IC&5MuldXKtL*q?W%&y__}JmkpI0zA|0_FA zqQ7KE{-^mLklt);s04rhtNG98KbikX{w%Kj|MB0Me@p(2(dQ=k4U=_7WoGbRQ{D=D zhxtL1UE^h@(j%@tN6cE7a> zQN~W(Gc@E_b_drvxQ3i9A?Ep-&Liqi)~iQr$W#rf|E49IyU=X#9)S9jYOH^y&x=c~H~o zso_oyw>13E5+2zu;l?5jr^e+e$7)P@Tfj6XsQZG(IbHoyyP3xQ8fUDAoT~1Z8s|*$ zvx2R}*C{$=gFi(+2m;2mP~LuUL<^Ei1U z%e>w^ANO;4x4|s1Q|3Jp-U4>8qQB{q`D^3fGHY*|;y2|THr^MG^vCblkWpHq5)E%- z?i6bBrU7M)u<}1oxdHbAc`wd9)sc#OJnQ|N<_HJ737A*ty;o~GH>>{^ec~fpy62cN zH;sR({{``zCq`I7-8@5F-c#l&MvJ4_Fj=ou+*>5Xr2fLao84ec^Jn$X6hCVq3&nzt zIk>grnqN9*;yxeg%DwChg8!+=X#Atq?{Ul^mo5( zi8sho?ojtj4ZklM!W-r06Y76J-Y(Z2@l4jzmH1Dp+o;doq)(iu{%Up4Quoj5F4r{w zqW*K#KTZ5bljMq(fAO1-X=-QdRjnU*`%%JGyB&YFp2S}xE(?T;6fM<|h1RY3S7~@a z-4qFN{9CVn?GTAtul~8>XO&+G`CR=I)!*A9O`~1?AFEq0E^7%(%s141QQfySysJL_ z0}c6F{j1d9MJfM`#<^WXDlJkrXKI{hHDtT`|Ed0~f zN7TPeQ*auEr1OHN@78-KiQjlq-gY;CwqzHPUnQJ%$I}Sus#hB{{?+P#L1RwQG%r^7 zO>vDin%Y4cCs*H{AEzPmJ`Z({x-Urxt3OM~EY0%@O<{_L+^RYMTtiM$_a4pvo$9Yt zcawoWvbwUQFi7cnp8B7Y)Qs;nZ_jAVRqD#?*`|4^#BrG78W|er9Ocwij(LQfE^&-k z&8u;n9WUVirgxpI@!!(2Y|@Z>HO&ll&lJ}fFZGxqZ;YG9ZvEb3o8}~_-)g+0aW+XQ zcneqJZ`OMUs{h}t7Ei6N_hO^sU#~Lr3hVk)&uhpQ$2s_~b-ajsk6yh??_DO(HP6?3 zU)H=GsVQrVY@V+E`!)W9O2b(i@{qbq)qU1Di6?H+d$l!Wg=nZ@CP@hEbMv)|`J%@B zho*D0`fpYDJ8@YDS7@uPr>QLk>tPdaYP(FG15J=gk<15GGVfCUo~Cgg&|KYT$5(fW zxDGEX>C@ z|Bo8SFYz62^`EBkCuH4gpn$9QUH@;A*`$FTKsQG_bJq&=N3VV(t|LkPS(?HVnnI(-`BJYs z^lEp#`lzN;sQ!1=FZ*(sjxp+QkWx4XYy59Cq*}|8qalx}TdQSRuKtx;mQwLMP7qzQ zGW4!~n*P~)^>4g#V6%DUYz7*=$RJD4wOy#6hOHrgDrBVuWviOaKB2mUv zNdXNdKjs>ZGg{MpzZoG<>zDrr(5_jhaFajoDLU&e1r% z)&HgV9r~@9`LTpJ#_QE}N}n|R3;^!C1>~7eVTy zC5H5!L;*XE{>3aYrbQo;j$Z@ba zlRX?p>D~>8=-v&7vS-6Rq;fyU5$xIUh*gu! z(lDE6$Q})6ut&pO_N$QH7p9s&IeMBGv5&!p=68;eHOOo;M!_)N|1{TjI@@7&8n&lj z{24;e5 z!Ij`rAYtgQ$vdDX?|_d*Jt| zrafu!V1tqnGG1H9H`P@;)womruc`YVb>CB0ZCT@M^`EA$THBF&^BGbbgxs+Qu=>vx zH?mlI0+Ge?6m~Wf_j`5iKIABk`9owkcl{vYd~xZ44$eK^gFT)1V9#`3W|Vcj`|5C; z%gA}V;WaKte!gITkN1$Om;dYeS-x<4h>?o@o$oOJ&KGchr{{T99G9U36B$8>ozFru zPUVQ5PheM;qc~#cG3J5n3)A0>oqL*P>_n5pt}>m^Y3y+$kZVqMfsy=kHd>9XiVf&G zkZ{UM{{sr`GT+AkjH3wGG8f>Uz)m+<7xdnE>)U(@x4$Vp6p!O#+!B*L)U6>Vy;^#O z5;6!~GSSvWxCfcrafdnj;=V`iXtH++uH!88L+)xtJFphaakw9tXAv@mksi~!Q2fSA zB3Z^KDqrIoX-4G+PcE3WadV>0fO zj*H;DOLk%*De3{kK|L_QIF}ttjz_vra-3#N(;Y!CBQ_sG;r`$lhHL8HY1}05MDx|L zSPChr&U3=4X;^OZW$`i8zg%U9i<8)Mu#$Zo*uTL!p1q%rjcl-vi)^<}jC^mM6xnK> z5?SvYA1NWt@sY39m9Gy{(925Nc!#k}QfCil`F`5NbBsu1M0)Y!`&Z=Y2(?D%Ut}p) zmUj*#WII^9SLiN6TlNYiUSz{wq4a0y5%Y_@5^2!$wusmX{K&ZxdBOH~b|X(ksv-@M z)<}IU#mHw+CO2U>4SUZhd#}mFoiD1`HA;59SZ>KTndx!|lE4le?DzGeh1Jcz8*j1S zm+UF&i0&!*k@YeAT967?7g`J9K&4e_q_UI7Pxu#Ei|{YD7PBAM5^D)A=^M%Ht5FSS zR#+?GvBU7`GpvNYDoytD_?Tx%ipiQ{il&&XDWZ3my>!8IZvXr zXR3r$u&?MHjHTqUtIu3LzF;q*YteBz&e!7zTE}kar;}Zoh(r5ZXVh@~!10YS$9NCC ziA{ob8Wp;K%84prvNy?#>_;LyktEVnb|3jt_ZRtIcNK|BqE*jsA&t5tS6KJxzzRev z(OBG8N_t%6SEMtn|2N{Ei0nA6%1Fps1bzm~;Jt*eBzApdo7KShiAeWa?yVzy9rtfR zx`WoYkzK@`i!0X~xL(Wk8m@2T`Wn41SGI6v16Sn9ySTE|`b_Vf!;|FtZ(Lu`^`E)k z!u8F1-AU*+Lc@fH38hsdq)z@rHja(3hg#%Iu5Tw~JJ;7+vm;$7$+wi`TT1d3CHYFz z-%Bs8w?r=`eRz3nq&1q-j_8v@Mt~SQNUzR%muJ5ZJ^&v5u4eAqY0W3j0`N28%OXvr(#rEf&}A;q`++n)q!%K+5b1@;!3NS?O*(5x zr zjUIN)Jze&BYmOg{$f_P=T^vTjvrDXBHB7=24)pKWvBo|R?q`E{G**tW86Af+<;?Bu zyAwUm+#WlujgeU1#~7!wug~ddc?ovTRYtin1Iv0O z``0{(Eh)D3QP|ecv(ws_9H(McFK55A8e=s((*!v#V$LAM*J@!Jnaj;2dihs7$J18K z;7&90so?+?aDpV@0?8l+qyjhaL_RURz)vk30BIl{WPnUi4!VKvpaS#&1L!9Vq}MQn z-ExMJ_hSg7bu!RG<9KiaI1!u#{sc}2r+`zzY2Zw74(-ah;5=|X_%pZwTnKK9tTFD5 zEHLf^v%vk}0q`JrC^Fx81Uw2JNM&pIZLgPj7 z5_lQB0%p?}dK;d+V|1g>aw@%;OnNb1<0ER1Pa;8M4z1z0U@rI$%md$pAHaXWk6=FO zF8~WcCHM&}ic}kmIah%tU@7<+ECbctvx213xvS#$gf72=eB`%5Q(g! zE4;=uBQ>T2SilLAA{$K?NCqh&6*`Kwu}s}cb*t6=Ro%DLU9IjX>SA3HpLPJ3mKC>I z-L2}n9~dXZH9(XMT~k zSgJ8P#Lm&HVLL_QX{jTjNK5S5dnDNDU+Q*#wD;n!k36pDP1u(&$laupKts7EKWw?C z$XZ&&J$}e^{D-x-JXXfYmRR2H%bnu2k>fDZ82{NhipGrP>s9$bvON-v$mkjQ5_iuZ zdD;?@IgR))N(-fRls?UomzB<2i2b@q8fDyG$;%?>6HF{q&`Xcv#9{EnJ<2`@qNc=}GR@(nSjl}TXP%^ycj~kKyi${D{T>u=?g}`0~i- zdR`Q%ebP%7UO)f&xkBjlxz9F(&&XL!k9wSM_m>2l~w>k1F?mK$z z!^j(vCA35m?~TZs$oG*=Namu*duViJWNG9#DVyRg&TZUB{-nPbrCHe4uE^@hM}&nU zt0D^{bJd5OCvsYz(D`SV)DE+?L;PrTTVw(KLaj?8EBIfe5Dn-o&#|;i=;n%VvD zkCECXr1Jy(`!KSRT6eWgO^x}bx*{)jt0422{FKMhnjLA{Wy=^;SBWR>I*rvN^<3gF z(w-+U+gm7gmy8Wj5cJGVkXuw)1hh)XHDq0peOD>=rG~Ohdg-_ZcdRq9X zHKQfnYpg_LMq8F>9MRbr2ex84Mt_l?utC3*4 z&RHebq2A)iPm%zmLa|Y-y=0)%10-%6mahKD;XY}-=N-TIe}@DlS{}c9hiV%!4%Ju( z;-(p6qIC`S5PiT*xdP3z^{f^E{YClZfFl`K>TZ{zKcu!YTJJ=;|3~uK zQ7TOVxwn7RIh`#()rQ#Bj&q{yM81lJ$7;-u93-Z;FWXJ-q(-6cS6|q+hSVQzojOvm zYiha1Jzv=8J>AGkY$$tVbsK&7=ub7+%UyLEVBuQN?xDn@^ir6TN3&X*qP&MV`;Tx~24{%NZ#sVSe#6qZcC`ml-Fsn$A^> zUCc0M^50#|BVNOJ#aHat`wb%-vzbR&XDl+BjP0z#w1e>t`l@ECv6@lb7mY1Ca=SxE zSa<5kZL5y3h8Ux);k`6jcg>{lm_o1K%Udx%4wHOj8Wy=K!(YxQjAis>+``mRm@dq8 z9*zGP@@Fv?a|Zr1IV=Wym_K0V|3cCmZ%pF;$>cXlbMM!YngBb{&qQDOjLm-)TBhU9Kb5-E^e7Tt}+A>DYI%j#roH2zarMT9@dk zb(xNXch#}$QXLKNsw3E?l!N(2=qED}UUDy-@Ic92%9Dq5IF%o1$_Wcj97xzf#u(zt z*q95RoJJhshfDd9o4}7e<%gyGNLPMjC_lO&Q+LBB;Yy)$#iv{;hbxaT((@=sx$-7S zdDC5aBkLr+4jtbx7`cEqbBwNV*qzaGlJ zUdq27%D-MRy9WIYv&WFN`#8QD^3~w>!OIhl*@N{M!j;a);9CZs&+7cKBWIu<11=kI z+<>0_+xst-|NFlVX7)c@kHY?i{eI*asP2z;{FvL%wdc`yZa>$Muli>6$?NCp9f}@{ zdM6&2_blvvdGE`k>Dy0lre<*rK!V6~?&eG$m!m|o9 z_}1YnxufGKsN;))j^j%84=;FK^Ye5;UjB~!rTOpSUY~yy(4)%-U7qgpbnZw{oNzc} z{_F>`uZ$g8j?B9F@kOQ{CFf?ont3m{GP5|NE@NKClj&>Im!^M_{tm~|^heUh1h)Db zee?AA*vH|%HpS~Ib`B)Y7tRc;QGgVFta!qD!g|QMO_68iIo6^FxoFu;+6bxtXKMX_ zr`G=;8f%dIYG$a8HNqBiR7M-~pr;rS>wfEg(~wqx$>i6p*G!l7hV_P-EHhVTis*ys z7JV>1q7SCe`po*wOk)n~OEaB$tZ&T>>wD{aGgDd$GfU>N%x>&?zs9Vfwi$p<4&;rP z!R%Z=g!*b2I{h~Occ`!4WkmjcH2p)YwU3Mf>IVm|N#E1~EZ_u5zy*>)3P=TR-~nDR z9!$Uvn#g$)m`>08YV493ShLrFYr%EkdT;}Ml^elLU?#A*a}9UYbH~rnZ94XNGA*T( zJoX@uCFHRudCVq{h2$@ZV**y=bXx4IY5QAWd zDnJj=lki@kH|PWUf_|Vs7(f{ZLdik+2ZJF<=upnXkc{EjYa_r&Z~$Qkf`h=pU=$b) z4gq7pq2MrZI5+|v3626sgJZ}8^PJ3+tYw~LE%PL6nI~DxJjq(-N!Bt?vX*(0wak;O zWu9cMaXR;$0nWrfmh)L)95@@C13%9N=YjLVpMiWEa3L7a^$B1im;@%nx4(cXU@Djf zE&>;WOTeYzui!E;9iCi{yj%gU1b+ipffdbk~i z+hMpJhTCDd-3qr`;dU$BZiU;eaJv<5x5DjKxZMi3Tj6$Vl-s-D_Aa=+3vTa%+q>ZQ z4!FGoZtsBGJK**Xz8*2*xdT|h36g*dB!d)?3f#a0yueQnA^_4rI>-Q-pd54q-9ZKD z0R~X_4nzlsQ0oo@#}IZbI1U^SP5>tY=Ki7HMyR(D>TQI28=>AtsJ0O*g`iRhDutj@ z2r7l3QV1%Aph_63grQ0ps)V6R7^;M!N*Jnyp-LF4grQ29xyKsj9&4C;tYPl4hPlTY z<{oR9dtAxf<4WcpS2Fil!`x#HbB{I5J=QSySi{_74Ren*%stjH_gKT+V-0hU>#0{= z(Ry_N^=fx&%`>SryHIO(qeU6PJYx&CFwa=SJYx;>j5W+N)-cal!#raR^NcObGp=Nwv4wfY7UmgS zm}hKZp0Sa6#zy8D8<}TpG#bEauon8Q13}OPnrWZbgAHIK_zi3Vo52>a6>J0BK?^<2 z9i*`nw1QnA1a>1eVd}0n&<-MzwahcFWu9>d^Nc%~XWYR&;|?<^vYvUy^~^J_XP$9A z^Nj0_pOCg~NZU4~Z5z_Yn-stWl0gbc1#aL0Uf_dse#Wx`APuC043G)3xF&B-aNr$Vd|4G^+}leBusr0ralQ%pMXR__NtpU1OnnljJ_%Ewgwcp* zG@==eXhtKN(THX=q8W{7MkAWhh-NgR8I5R0BbupC!qg{WG^3gNBusr0ralQ%pM=qr zRy3s*O=(3_TG5nNG^G_yY5kuxWd>HkHQ-us9k?Fc8>vEjs?eS)w5JN~sX}|I(4L>s zo}ba4pV6Kww5JN~sX}|I(4H!^rwZ+gei zcC@Dv?P)}N8quCcw5Jj6*^c&XM|=1h5+p^M(4Ho=rwQ$8LVKFv!UR&a?Z3s?Y!f0& z_-_T);Bww>*umQktvq)<&sfX2%l=yAeYL8?sY6D9k>G!A;iP5zz4t!GGww72Oazm_ zWGvplfGJ=qmz9(K!eTC(M|WXoyEmeZ0grzLxpmh4qpvR7%z zUZo{_6$uR@p+O`xh=c}_&>#{TL_&i|Xb=evBB4PfG>C)-k>B5$+ETPM6>!V}iWXd3TQJAeh8APKlYGDrcbzzsaW3leSZ@glikBA5j3WlZ=! zFbmud9sm!5hZuo<1Uw2J66{Ylu(&urht^+!FTq#fYw!&ay_ddaGhArX{@xG# z_bnv|qw~86T|^&m&yap_DF~N>a486vf^aDamx6F92$zCzDF~N>a486vg4mqvc+xsF zbsd_zjucm;Y4vDYJ(^aJrq!cq^=QXtD4E2wLrC=oq9^-@QxnEA>d2dL&Fe5~dyrQ;&qXyN0`KxVwhCYq-0HzJdu&9l!!k zkOW*H8Ki(z;0Al=bOUv<^r}{q>S|J5O{%L&bv4|5o8HJfj5EH=$oYr7Rs33{+L}Wi z60h{_bR~%rwsBuJ_j$NauOh)x=hOQ)J-om92AIt|uvnYcSG?`XyDA!EJvphg?&p2e zH+WNbcBGydONp_97`u#fX&u_IsoJoq+OVnGu&LUxsoJoM+OUh-u#4KTi`uY@+R)xD zv<_Qn9k$Rqv|+EbVXw4due4#Wv|+EbVXw4due4#Wv|+EbVXw4due4#Ov_Yp|;OH-K z^cOh#i*odGawF@VsBi`zlZe>Olj5s!+MXdY89n-v=Ln4xa3!o)i7O8lK;;@7LCGwHkh`jPk>T zrw(8NCrAP=kPK2lDsY2DUW}(^7mHvbm;|QN_V0_XS2M>tgEu3u0oQ`-!1dq;dIUFu zo4`zPFSrlP0{4Rlz=NQ3O}vqscq29OMrz`X)WjR9i8oRcZ=@#PXgmv^120hfy$D_c zFN0UWe8Lxig`g7r1QvnCpb9JjOTo`z8IT(ESLnS8)PZ`?09NznG%Y-DEid7%dv?paQ{yt%_{iO={2)Pj|O_m1FVh_4rVz{L<;48g?^ z^IhZk8oh)WmA=dm_T}y8zRarhWmYBKSPyt>*;jA-8H_3#^!1oOEaQu&GQJ8eGkIUzG>w4i02Xk9B%_2`ni4Y^q<~c5Hcl`- z#wphQ)YI4&NZBUqd82@DO$v~TURE;eUYkNyl*n5{1#!ejT@1d zdy$t%k(bYr7a9Nk2l6rodAS*R84mx8_@*R5SjR6cm2@m zE@|_mZJkT{?dbkS(iQ#QM7kSEcc->_d&FR#bPiute8rbO`-wrG=1?z49U(EKj;1GN zq($q6&e|W~>UZR!iSq8Gykd6+$GAq+_jc`eMg!#q}gCCB#%FV)ubxr{v&s9 z;%=#Nc5s)>3IDOXI-V)d@^aUYl*30(+oCyLPcGM!%eCaPiCoU(Ia_$ncAirMH)kO& zGHO*x{a1&TvW9nBTIiqeHr!~64~^)9MhrsoM&)c@t~qH?5ENw1QH}YZ7&d*hlvux37ZN!0X@* zWcW?+7MKm*2Je7(!F%9+@B#P`d`kS!z~}hC0AGTyz}Mg#u$*g+%;~zJfQN6+UgAr& zH;}8@=<*z+JEiZ2ZoANH7y4XeEd#5K-jp|kV{hv%m6ZIXluJrTnUOwRnQARliP>xJS=WTxZ_sFS_ochSAkDU6*sgIoc$f=K<`pBt| zochSA?|;l`9y#q9&1sJWer1!(Y;u`FE;GnwS8~~vTvm|FEa!`WvdEOdohxybFwbTxc)DFvd zPDh<1Go_-ZsYqrvX}d@}m9#UFU8&ptPwF(8F^=`yG<}}V7jsZ-A$i?I8?cc)?jVoN zVK!6+|@xn52fn@hXQaY0}eT%pr26@XY{%9U2-embMEGQPG)1VVP|8*zJvYx9&+w9 z-sG8YG1@pA`}S?@xOa@+q%=6n>+9f|;XRW8tT2G&~o<3_meb##Vto8I+ z>*=%B(`T)xpOiSFSx=v}o<3_meb##Vto8I+>*=%B(`T)x&stBPwVpm}J$=@C`mFVg zXl`IEeFJ0Z8yHL9z*zbQ#?m)1mc9Y&zZ&bmntoC>)_*nDe>K*BHP(ME)_*P5e=XL3 zHP(MM)_*nqq-rQv4dtq_{;Q#0wec)?4#-T>3yev>2wnm&gIBDzlo6}lj9Bev#A-JqR=XLo+Rcd7ZbqzjGh(%y5v$$Ce9~S37J^Ff6R^KvtHye- z#(J;DdauTMuf}@ky)^DwLB4A^{{m{kO7JT!@G4LT>OljLR(TEiUW;6=13}OP3-O(1O*mgSQ!Wf>y8#gg_YkMc#IA2a(8f#)+0QPPErd5|R_L z_(B=U*@gAJ1nYYV*7p+YBk*tVF<3~PpTJ_qN0xwUdfY2OJ$7G%*rU`Q9w;4-Qn?GV zTLhJ*t;t3UT*zn`dEA9OhV@HXRwh6<9l!!kkOW*H8Ki(z;07L~-3$EKhyjoW(m@8u z1m&O`=ng7C4=@~>jsPRUG5mil;A>xGHi*myk=YN$m}9yb`dhW2$`)!W-F1|N@TVY znXN=-E0NhsWVRBStwd%kk=ZTC>|$hgF*3UtnO%&`E{@g+b<_wukzIL@r3~3Eg{nQE zs@QzIPl8;}VP^4LFc*9W=7I0Q58yxGM=+n~EC35ZCHM*OeG$FSO60c^`K?5LE0Nzy zo&ef#3obw9KHJs~7vqAb%@a$nEoRw*S1)LxWxIi*U0jazvZyMyI9_qDpK8jkFfW#B|hM6kMXyl$GrK;eV+l5yw5p*0lozEF&Jgv z$te5IKOm9wkjQyRyWMuNY)0VO05Q!DzS>i zT38O(exq)1P&f32Yx34aFE}Riz9m=-Ta{b2j1#P(6fMjw?nW14xshB%YhqI0iOkYN zBwaVQPb0QZ6L+*}ojsd=?i_0Puh62o*c7r3g0xy{n~J2gi;HAg#EU>la^7HWl!)Cy7?Y{cr6bsHKfSuG`7PRUkLvY#p0O2(l! zQVVRPHQdfR7u#qNx3kv8Hr9jKVl4x!X^s0*@;^5I?7=qig5l(F1Q-dRDJ5M>N!L-* zb(C}+C0$2J*HO||O4>?ETPbNPd{2eP4wbHF85?>Iya?WkEFkw=k+Kj{7DCEowT!it zq=}OJLP_c<$s$U!h#c=?bYcQ;huBZ9WBky`_@R^WLnq^hPDU=A&@+VG(pRTOv`3(V zq-3vUv0C`pDFunWznB&9djYW*!0!d{djZe=8Gf&Y-)rIbTKK&dey@cBE1 z__Y9jEkN?OAo;?#W%NI%v(8TEC)~#q?%mH5?&AsX?Dd3>6z`=cFq>YY{g!MQ+A00i zT(q+*Pm!^t^^{{NdEZIicarxI`Dr3QO=zME-d?RWaxS_pJ@_>4^zyvjlqkNAiS`vT zi6LV$Vr!+)cTJ(cW)Lf4&1Ed~2Ub{FgSJYqV$Yb;lP{xZ*Oi!g#LOk8XP+?#60;96 zdlIvhm?gwa+h@$4#Oy)LZV741_a=Kjy`v=UNMsu&*nbSES9bHna%wn}y1)S}-~>s) z1(HDuNCj>n)SH8a^evbRz60~X_uvQcAMhin1~ovw5UT|%85MmNUOWe4Yq-42SlavG z1HfE2^>rKdb=#iYK&$L^U4E~$S{6z>ox0*`t(9foL~79>Jd^co)==7JWO55D37Yhu z9KZrjkOW*H8Ki(z;07N08(tveE%%}&_kmg9e((Tz5Ih7P0gr;mz~kTv@GtNrcnUlX zo&nE-=fLyyTV8;gFM^lA%itC829$b}y5lX*v%%Zgqwiqpze^wZJ^t5`LCzl{bMkfo zqmXc72b|aeCw9Pz9dKd?oY(;;cEE`p*r}~p1+7>GtwtsI2`mDOK^0g6mV%$bGEmJu zD>&D1{sq*6mEc#}pH-j^)Pn{fZPFUbvX;E?eHnIY8+K|Nc4`P~AcQp#!Wsx+4TP`; zLRbSKV++^{_|6w=K*kPsVhx0_20~Z^A*_KA)_}A&ztP(4q_x>eYqOKqW+$!9PFkBy zv^JY)Z8p)`Y{EL&jdida>tHw5!EUUB-DthEKJ`djJr+V33qe*Qs;3TLO8vbXsoRaz z?MCVn*Dz{DLUti-_0-|;AFl6)1Nm?u4GwgSK752#VAnNm+Ac~xE$_FBE zK=Rfhd3B__4#``u^4UbJX3~{8ZyDVe8(tRf@JDz(ZOZ|-LG zFp90->{VZ;t0MI#%)!^%t1V02RCV3z@`VN^^{MOUtICyDK;1OGnyzjJUnu`(WvZLS zw~`yIY;_Cut|E0y)h$!E8{c{Fvbw9w%1Oj$?IhgZ>h@8$ue$xz?XT_tadj=6CahFh z6K6B?*m4eH=gPSmsg?6atbaML#hQ?FBbKe4Tj0B#>(L!KuY;$$s!lR1J{gWA-tJ*Z z!gkkz^t039&Hwb{+tq}x$oVc*p1Q{`aV;CZGjEm4n%ii+z0!~p#IA+;Qakz#){E)% zb#7vuxPKMvNhHLJJ%_JXw@1E;d?oROlYHsBTqqg&4+m>I$Pr5;c2>&8{)wK2d$AzC zwbk#Kl>@Qsd(tDJEV29K99x@0@}>VL3EIamk-u_TCH4=*)3}NB6vWJEgI&vLuu> zc3YzC#KK}{zHQ%Yodw}t?0W1R<1K5Is4T=}K7RdI`tST$U&vnhBuc;7^~7^r9`}&D zm|hEQHLV2MNW5RKiLN1EF&U3t*BXd_Sm{B(7nhndc5Q#>PBaxhCj5jx`=rsHx`Zsp zZrhXIqQm=4V-Nnx{jB8@U1o8m!yCArubqF)LhsNV=5L>p4#Xm>>DbFpMKDLO2RzL(QVVx`Me%gy|p$6_ZM z%WL^qN!4!!_Pq^#QN)o-5N`n9vH zid&>*aA_HmwG5W#K1=iM)O=@ZzAepns^;5m<&tlY=G&|Jc504&n&S-3rK!2JSDSTc z{v4XWY|USi<}XR}XRikv&|IeJSK0y1YnpzgouX7{ZlC#BKO>SOrM)(C9d~kE#c?Ue zWDfcNR1W$7xP&8*wZ5luU#^r+$|fa~a!IMAG?IUE+{fx`^|Sh01NgG`4f@ps9PN=W zB40Qn;#vmlKz(4D>N-SPv6{qnvX0$+D@k2?YS`%X)o^(um#c1dJ$lv4nh^`Jsl?^G z9IRBn%)w35IO*zUXv|D?v((DURyRjOa@EaKw~Ia{U;PE@7HY~x>UPzTQuUXq%eSA5 zmhkl_ZiS}VL*1Slv$y*DsM}ZFe(LsDcYwMBHRd33jXY>WDWQ#&m6;|+&P;WkY7Zu< z>rvM$?Fr=;msK>e_*h31H%G7Ls+*^7zPbhK7Ha$=b-QXvsrt**?WrLH)g2@*qaduC zgT>FA+qe#~0pO6hj1Vy1!WaQ=nuesSg7)u1PH|XQ@FX z4z((AQe@19HNTk0iif45{j=4&>ag<&?}U%`6*Gj%2ZTg|&! z75zSQ7VGyv#(JmaW=W*ZWTjFQJKG$Je+1{L%m+>b7lG-K1?J`83cyz(Cf~uBGr%?A zT5uixo$EQ@0B$7CO`KJIYF0@p8*ul&OPeYpLm)sLi5% z6KKFVZz2VSd!2u1(jGt3SR+9lIkh8nJg4IZ%Dh*K9aqH{m5g}rRKw!3O%4-EL$5vh zi}jj1dbP1D_8I-9Z)V>cjhnQ;oM0`kB(B}>WE_+fJj{9R=NFZFwHPIe+!xakdJP-t zF~oc8{KxugF=}gU=HWUgY_B$lJS-rlmM<D1>38U?bGi%~4~I`2#NL}MtAD=TaAI{?dB|F2sJxvV9U-d z#%S!m7mYD$OC71U)KO|n9j)u$9E(M@$T&f*yi>9AmKmq%IyPtO3N~ZO(-6}~o=nXX zJ2T3@A7+VJVx*X*W*Po+vz%OZGrQxjFe{=tPBr_Pg9#aG4khL=a&MX=%n@8YfHIhr zL3T)-N*Nql28%LWi~lXCu95>)+2O3P}n<$%uU1)B`{}1yPBa1yd?jhtp^FCtE zqO=b40rLT_K4d;@q?wPJj~X6I{utp;m``AJ%Kinm-Rn-Udu_WiX7|cI1IbbAS9Tl7 zQ0p>Nt;-CxE;H4-^eLqRYGeA;D(3A=sFtp40Qq(GA3szZq@469)m&yVRP#nDCH(Y5 zoqoJQH^3Z#JIEYF?uS4l3l3wiDs_^S!|6&LH`JK{y{>^qS&ASb!?Bs+0UMT2Pc}Z2OrJ9c; zHFj^op}mDbf;FD65|peGl&lhzl3xZ9(s;anp}64y8+#sZE{^?21O#}gd3?+(saIVW;lh41Vr zj^TWa9(Op2Va>DdaNKEbhnlRL4Q*}xD=>?Yo|3r!xmEwXs((4Ee_fP21ka!#mxqs)Js#s*Z7ptg2&-F^Wu9axwiN0MY=f zwwSqqRa?vgPzYG9#bmV>lhs98mJx z6QysW^i>I^Z=&=~l)j15H&OZ~O5a53w^RBiN?&EyllZA4X<>w;!b#SBFZ8K%{kB!Y8%P8ltXM5$NlUl z)`hpqjR|EHBh2B$hYT51TeruQKs&F)KJV~cdb_IMXjwDBnba+#IX7}7K-2(1`?tr;2PQm-F2jeBVh`r=uC49iTDIR{Y z?$GFvUW_HXN%rIGpg2!Uqj@h)-iMDuk0`hKoLSz*pX@THyK)1L=^hW;pr(7;mlm1X z9xvP0W_a4y7n?(4;Ufvm{$Ugn@Y*w@N9DL3Grehk&-otz?E%kNci=Ak?m)mj-j;@9 zxUP9qZi#h{G&ndR({5NJdl~2QzFIHCxPlyIB8lWRC)w{vR=2#zkio-846i6J9})AE zK-W8=tJ(dOY5jaDJ^E#p_xAda{M(uL-_?6$a!S|!cNfg;H8eT7u-9z?x8qKaf8e-L z6(h=0GEW(C*q?{|eQ-(nz?=G%l<+1AtJ&;uEO5*dnjKlz-yu>l+A(Bsu|ov_P2j<0 zh=B-#WJA>?*^eoA#3jcRdXlr45 zN}BJERJX%_&{0lPM)~<8o~+=;`z3xV`C_fn3W91iU#JNr5D1O7U?Qbn_=?d2%K{eBNPGk1q6> zX{opSJPyZ*{v%GxaHpquhm7cdOqb*|-|eX$%X|0*GY%_s<+!?)rlgLp&B#klOG)yi z`@HGNrYpnKrcx%mWXtNdaT$y97%@`;6Sk|6#bj&yp_iOk>Pz-}a?iMP$^}#V9@5K` z>`6`X4nJ(7EmPf&oP1c{!}^?e?Lo5&4jfR_zklHohww0}X2((_QRxdQNa<> z-rr-BW3^2AAhhd%0Uoy*K*9%(K>4;Edg%$J-W1KsUoM>1hpeQy$;z<9Cl;UM_Bi~+ zIVa#Yy?)P;9>1CF@$V~dv-B$D6Q!H0@|C6XHPw(|od4%@j-*S@pN6(H83|Q|R?hpX z;9{&amq5}isl~o2HhWQvWlHT<)1j;Pt; z)A$HlM9>bGX3P$sYA`UekMJpcEZz|=&6^#6f>D_eE~0FQPh>ctBYsEvlMESlh&@-D zJv;s-yo4%sgPXcRD0W~+qgUEd$?lhOd$xSv4m&i*ZF!R0e~i_U3l?uVoqg=I-e zImKQm>@hPuwf&Comsa5251~8Sz9^F)Q3d*4Cet9t`MZFpWD8H{cQs4Y53lP65fXdg zB#-~WfM=pR(BKa6jGol`byS%!GiD2PuJ!vnwAPQ-jZ~ma8kNEGsQdNfbNI(PjQ}4hSCteFz39CsZY5Nxn^vi z3;UjN)#&b{kL#A|O->G!<{f-k@3Z$FZEnCEGyGm?~dy&O4`0`5VQnL+MA+wT44FRDg6RNZ?jwWqLV zf~XN=#^x!S@3>4#E`>HFTK)|8?a_S1Bu>gLB}UR@cl8|J{S{f$mHB21lh!w z$5SB5_;xK&A1%;i<8c)S3I9aJO2S>vY2!tBB$UnA5fVFeO1D_(ay7y2&o-Y97v;<3&vLu4461=RPUq_gC*$k7I(+s*6K#2Vr8#m`*rQ@woGq|qu+2;zGU?==n0Bdm_`Qza zeTE|%YO5({HN zdr3zM5%&t8!a5RUP@9(@$zUfth6*XBtY*CbCg!WHtm*EX$jg9VU0LZ5`IA%H7k-|S z;ki34&H2bMM_Rmstf_PP@>1KsYyaAp9IGR4;jx#Q{i76#3+8sMhoj0?s)awuF1+!CN|3anXF29MdpIvO&v&#sTr8O( zG9)mgOiTBg&qGcPm=!qVrc>$zZnQPKEGOTb z*8Y$*V^X&Uob5BsYqiX09X);sb-eT;zs8!#=F7}j#UUDL_afnH5A8Wh_d>doQlXiH z54q_0uAY=kcj=oCh}WB(=`MToAHz>c_oOHLD2jMeyaU~3M@&AV&)7b<-(7x`dj5I) ztT9LRJ*oFmW5yiS`=q`{je&Za0j2gaQEH#A)U(6IO0~nM@fv|pd(Ze&qz4cW7i-jx zKOt&V>=}O&p9aO^uT6OFUs&KI7XG!?_I5g#NP492ihN09*cMISX4E-pnT{l8Sbz@DJjMGy(-3lg9=qMIFn1dLyn)IOIHLXP8X38GMAf^C3z#)J$jUjFUpAWa%r@r z@-@@`er;}G+^91c)=NvdHPdGuK6xPF7hgGGWNJ$Jpet;CTz$#WojNRPnG{24 z85^tUp#wZ|R#T#(Hl=fNa&;`r%$qQCL<&PxGyPtdGp|p{fk(Mq1&5D3_WbU?tfy}p zGwF!pB-5WtTanbiqR)ZJN!bSt8#}Swm;JhXpXSZZa0Q&s_zHu18B|Hy?972Ag)L8JoV zeh<y2h;rcJlku>*NUbo|%{CDm1WMToBvv2r&pToO%DNldz z$fFKD;?glb?`an9_B|b6_Fz!JrvKof5k!9Tmkn*((+zJKQ5$+{)t3CLcja%k?4?kk3H5Ply?lV z$%DjFA2|_+0ea8GlD!{U62EwWK3s;^27COEbY$TX4QSu47LS%r#eTes{Zyk)HTrlo z`aRWX35Ro7_@>c2+AX9>(4IzzEok>Olw;b#G)IoP=-B+gndI_jay!=Fd(^=v_{Uc*QSB_406zROoV7D($9hsA{bAOR(8(KDX#7MEjFJ_%YDHZ=Y zwo)ppds_Y;R)tO1o-f-+hgr7k#cy z%1App-EDSxD5YSgC&jrjsZ08W=|0Dx$DG;eSw6=tseZ4weP%;SW@gG7^VXcS)V3Ra zSs5v2aeG5b24v72D04553e|1O+&#mmn2d(US)j1exMfUhG>Bf zmJIF{KGp6&M8jpQ$c{hJl-`_!WqfuxCO9(SGvfY~n@WweE72**iT&@w)!IQrV zF>O$PsR44n9e8YCf2z}!L|^@kA)^k-Od|J}QL+h~r&HMEu1EVy`xg`2N=n68>03Zg z-eEb5-CakG9hucNYuK5iOUv`~wbJY@y}Xj5irb3%7i4wI?9!*8a9~lOBv3T45Qf?L z{f%L|UlkqUu;T~g=}c#tfPKZk!gwwrd~rPfb;d_g`gK$K z9VByqRGY(wLY{1GSCQ5I(NikSY{s-=b*B}hs}6eGbj`}iF=vlDD5E?-%j>fs;Q@n= z?d#h&nf-28K}A+h3N)9ow|Aq&c3OeryePFD-on~3gSreKoL1or6ctsJj2b&)56bt# zYBrPlc1_Q*C&ACMIgn9SkY=+WyP_yPPHX8y+B~?1WoJ8R*ANfC)_4aRSzOy;-H41G z1&z*+k246uqv=(CcXm%39OR`||Ai-uy8o;7GNpV<_fr@v%6Q;G_6`j)!fy^iX8^yz_2f4A-# z*~w0)FEwL8|KhG)x^yibcEpK2@;v_J?)`HzGTbh&J8fY9l0Mz~m0jLtSWkZ-r8Fl! z&$rlFGN4ON|89`bCW(mgT~RSc{7^^2W#Em`#gTT8E=HYL6QdTjb|>gU)1}*oI+|lf z9-omMRl&PCUn@0c@sWcDAKNeBwvt^LM@^bo*0(Sq~UJHax{xlg3xnjh{z1 zOR^4Zuz6?!v(M!D+~B$vJf6qGMVHM>9*@IYP29UoW+~D=lUAO^$`7xJNM6JuEtZn* z=ZLbAw+~1TrAg`Ez2f?K8OU=vUMS_VZ3cb@>+o<6b)mF%bwd8KhPTrk$M})NDYeXdS_S>?DBc5V6~!j$Znt3Qf|>qbw_tPy`t=~?6;cqe^R?sUM~lcv*qq` ztR*T6JTF=jiFiv`6il4il8}3kPp>5RvS#E9DSnlhtN1%O0hXMs0Sp zyYDY|K@2ukTX{!<`gnF_I% z=y(GsUA1K6Vi(O&WXtRQN4q9-R;wVHZLMQlx;jVPt~?}-1yn^&Mklc~4?0_*k_x8` zVq2nH!pYVMB#vNKQi)_S4A$VyQc_N?+|mt=)VXD4IvLucDj7vB5XlSd$41w^gv5}j|eW_-$j35{&nohza*R=^rOs05ML0Hfoe_Vegr|~AI}$bZhn!%VR| zMa68Bo$YNgZj4X1g+gsqR74=|Wqa>6x@Y9hR zDB8#neGQtII*N5z=Nd{V<`ZnzsUbIT2js8cdMM#AQ&q#qfctpZ6Z1-nU17K{?;cK2 zQC}^`n1358Z4%*db5x?*K4-%2yS!iWNHeDfb$Un()bR9m!bqwX_`%lJ=>i>qi~;ZB ze^gCVAwI1q8M~+qt!kmc+?5t@jSVnt*G+@ronY^2NgF*dyc;SEPx7i{MiejN0Y_Pt zi|fGoh}0Zcm5qv;ST&c?Kg7c9H)STGMQY)H12Xq1jT;w3D_cCG`*4+SlA7#oOW% zZ{tKvK5@`uy z|A$)0Y?lKHGuw^j5s$x#@%{yL;s>u?Gky+t?AFEwoAG_owCkzbC{LWMzvVRTAb4M} zr*P8vGepU1bf3|UY!L|bssrOT3{HCX8T#jLEW9l~Q(Cb(=@>8~I{k92IntJv^q>>Z zjG^zvGo^!TDnFx@a?Z9cUol?!HKSa0at-peR!~u8n?(f`*8yiO%p6H@$`vpb(WCN( z8-$O~Y6?StM$xW*6Y;t0K?{U4XoUxW!nZO)oI|Uk*Mt8s&JFS3Ls>|CF%k(`?&^*( zLOq1MgMjiJswBwAlN5zR;sz;7D(s?cD94m_1-=|Vhuj5WZHIzm;%pv`w_u({q^gpn z{;lT{^hI@}=cpeP`|fLa5|H{EPAS#V#=7sG zsj$)cQT_z~JyVt$ic-V-^t>H=#|wB8j`}+;yTN-nMA^e_0`@Y7_8}jcOpL14u5%!1 zpqfBgiqj)&VED$oCRA12M5u-IH~>Gz5^pq#ekSp(7;a-2b{m*>%b%Maj^wO7r%2pq zs@`)v7>H{!RHqPKK)td2*Yo6_>7ZY-6X=KMN4Xh*9-!>ZM2*lr3$P<;yA;^_KzJtz zpG%~rn*r8kfOU&~_|W9{4NkZMKK7vK>?4{Cp;t(7-)GQ;N4B>LNRQVs#3Pvh9xw#b zqII)l`l=YFs0nI4(krccsAM=8bDGu?tGO^U0%{6>lQwmH6{fmHQQb)|w@X#Fu<5$T z5A|ZP|&8ElD( zzqL5j|K$|a@4UjII_`rVccs8&zrHCe?|HQ(hi#w#jV&OH|NKdcOW{8+kI6uj4>G3S zeHkF2hakx_OMSkK36v@buuuU7S*k3$$N)(LA+&o)l4m|>b=a@SGS5k-@4ZG4c+P2k zK(m=HG~x@@ZS{ZNC&>sW$ig>%AXrQ?>LuRu4vOb97ViZDo@R@Z)qW0>kY`zyH)NI5 zVgS6JjQ+5J=$E6f9UJH4C@0C{E&$rPn-9tu{NTKo!#r5KKDztgtK0GOweL#8yKttD za033|Zd;J?aQ_VkS+1BwVlsaiP-Y)QIzajjt2!(;lkCo#bMV39#p6`oW~A~_4? z?7*Zwv9VlUpKuNWrDwrN0~R^rbLSJ%fH5#ADG@IX;2SmRnsUWGt@&(w+fC~#KVo{x zn=ZIqg>>Z?bx*0v&#Nnd_35HQuV>bgivT5#vc$KRSI)*9H2)Pq*sp|Ji$ii>ov_cw zo9Z-VM@Ls1DM*9*N7*(*!7Xh+&WGO+n)tDo{|P$fA@n#_lRV4;Bi0r$R286lB5|oI zXJA^b7QW5wa~`o+kg*olN^WPt&`-|*Ip1ot-edQnKur|xlATw-Qr#NYU5akP>q|M` z@M$JVXd45$U}b%LH`-1c%#3jox%&7eTwn!022$dT7<$}6ag!j?tcea-42 z20shQ>IKsVqZz+AxIl(Gms#^l$GS^fsDwt=JcT$HsuE?%I=`{*a5r2i+;h)dC{{zW z#D%K*#H85jYH0qj;dmR;IHG&~<++*Tor*~|yQeQr6?;{a!doN7X8l80?m4vD)8(Ex z*wb@x!rkRreW>SBPmk8Ab(hQC_|?+`*+KJfXMFOQ!6#-yq5&7#j{5k8hOaI=ey#y- zZ|(b}=JoHNLa*k9@rC!Cf#Fjfe?{HAx0A}Ry@yo2{+`P)l`xL8?myy>@@ZpSG~Lu8 z)<&yu&(bL4b=}v}aZ8M#zv~h+D+C-Ic|v#uyRwAf=*A_EtKSeS%X?KuEVNeDK@JM2 zB>L(CqVtTdC97%|EtcdCb!NaZi$ zawD|KR!0kWFYDX5A(9@%CZHq(qDTD{VWL2UT4WI>M?2)^`;skD3UQjmSTfNOMIDS_ zvZi1q=-Rk3R-ojA8_9>QNIoQ}WTd|qd(@OKkwiX3}Vo;8Qdg;*njPbLD_kKi$K zItU)uFl`tdKZdyjMZZ)vRsAU9?s^}AN%p{GPcIBnl7{=5y5%1HCdo$1FCR;*3TmZ_ z1r)7Tl~9ar@^9+G1y=&nW`@avG&F5n8W&CHFVg78V447;+URc7$#AHWdxDPuuPc`E z&?yN)6+mPVESy|x<=M7Gh!JBd|J{+z?Jj|LT2BjR-sX)5!!0J0*4f=T9gjbT+T#%zpMW>?jg5-7hy$-KOw&hk9^K06|O)c=b z1YYzw0&cs{r6?UEjqPg+SR8>|X3P7ovFsl**+%2K)1!}{$L)KxL^Hw=w8Y(pEGqXH z85m~J)E#77h)vwU%E?}3!VEk5u_cv2R*zHE%z_kIyD4r0YEGC$!RAXm9cqr4fw{$~ z(e67Qkld!_OMx_{S!(O^-Z0w6wu?EQH%__f1SjUuv2>1-EGFrETM#|Z8)D9Kwte$--KBfB6BT##&I zsf?(X2wfZLy7~m03R7_30)mQEEeh|rRv)xX@L3Y;(xaSxe0xGItjAOoUYkkd$5}k2 z?=(iPWKEvH3{Xdq6t<3kjD^_oG`zVs{ufN@>EFK{ozNG)PZpg%ewiZbz*8fn9>pLAjkq?>p%Qz7;fYNb zutX`$g(nC#W^gU=!pA%M-LlEywVKVGl-$+Vw?3jFsHhO``n_A51_+bv=^!eflxW;+ zc7>}+`)}tbiq2?2;uR^@n5o0={sr7xapnavhhUN==xdmyRJ^{Ti*z8lHcs}YK7NTX zfR$o}{H<7NfbI6>tD*j0v++B4yLQxW=*;4twU~et2Q*|ao7)Fn!u|}PIXLGxY)}u-)*Yd{9Ch2 z-KpC7{3}Hl&HEL_Ww%s*z(plZlPW*tVwhj4v@u85RrwX^cmob%hbIhnyNw}3hi_s0 z9OX7^-zT=xzkiDJ)QvBE{|q4&cFI?PyhB)L+9>kDv2LaYYv$DA&`>~=EZ;e1*6io( ziZF7~itpjLkRGsMIZWJJ7Uy<#_Wf~w4rgxRdg z^9}gS%sQHD743AEucpx6ZwNL9Lr2~Cd4kOtk5dN0`2K0!tU~(&nFExl{HS3HEt0CR zr44pPD01ObRfjLtj?y*RBL00Bu@X|07uG{=o+Z`!8OjCGr|Tt-K25o#MS7LT!E=OB z^#d^6@#=3jSf5a;`>e0Y)P^;!exMc(of%Wx({EXf5Nz*jlVf#jL844oD+^0!Su;j9(>g41?#7l_qby72=~0)u zm{J{?Z+x8_urOL?nU?t(iuaPze}(aT-KU=AQa?#7esw*QYc)bItd{>2R@<@MYM+68 z%Mgu2K97O^1f?q(g`nU;A+YD)UMFc;PYa#R_#XhOp5>sr5sWj?*1|M`bt~(M)D0v9 zfWk6C_UR@ADncsTJfD7A=&nH@;#yPOBiv>F<2aSmswe0mkU)Fp(SX63%chqwGbzRD z%Mf0sSjwB4+sx8LZ$Hl=pzpNFD>T6rDz^;|+v1!}8nQ?nZ!bu}q$%U~a-7UP(wfW` ztyW33SWv*54EA=vOp;|u(Ojz{LCLIHEmiI$X)SST_~o*?EDCROD( zNU>rbecCffXW|yK`Lhgim5c(|*zjq9DxI5hBs=Nl^)pUE_y=RwA7ZK=y!L&|uk1lh zKJ!LZ!TAb&s^O6)2m3%<^Y;T=8l5vE_95V_lT;JV)n~TM7)V8Rq1;CLK*bdw0vN!k z%)Lvoqu98LQ92#nMy(HUM7#36Yp0gy-^t&_2vyzfbyKscXu-5zM5?PgpRo>kyeXU+ zFpk$LnAl(+kkX~>jc+TR+Y_*9n_svK*<`l)E&2A4XpwUzZ$1??EdhqRH4r{`x-_xB z0~Ud-`7(h*TZ`n3`$3d{1X2DBDD$`=x-O{*tGR z)n*8Gq_P$M1SMX(0Vo{+2~=Jk0PWuVwT*x4_IE$1+MZO@)=j5ZJ;r4BRaJSCb&oi$ zP(RT-b{=_&!Sd(=0+xsAU43Tt+js`29-`yrwei=(*wV*O;V{R0u|;5^n$BZQqdEtR zlHgv*{}JH&Qfi;b=n_b>=oV_7hfQOq14s_?=082a^EiCA4QMGf5>hT#mbi|?>CFGT{F!C4OsiUNwdqm z#B)7r zr`Byb)oHV|cc&7fWZ(5tIn_I!wxXF&AnHy9vw01MmX^+Vlded}YPDO_tIMhKj-KpH z$kj6xAKu%eOA{dgS|k_574ef`bZ}cp-_Y5TD#N3YmEXdhm0UJbuq4e$+-$16#N<*n zh1dH>9OYhbLGup1VF&ku${CRic1SNFAiMxlEzEc&((q)JS1?Y}P9Hx+XFUvQM+bS3 z&?jm4G`v!EWMTb*BlxcYKj4V_L34-vAWpm=n(nSiK^<6-UGk{cl3mtn{X9TpgNc92 z0E;nzZ{}tRFx-sRfMhi5oqzxk3`?jMiIKZJBrI%BU=2}R8-MbH?%?3;?VDsf?-xSR zj(l2U8}erc0wEHFofqGBtdrN2BR-S4ZR4qNeGlrLHwbSy^^ZL_QpFcFTER0g12EaS zW&};dhDinCLcFc{YXTaZwZhL7O4(9n!Fi!bMY4VS6I2$+=16efXqMZ{Bw z6~dJa2eP3=CX#aQswqR;dWi3aI^d=tOVxdM_bMp=Yst5ajcjt8BtaScuhGp;!7N((M-rMmK6HMQB^r~^$D^OLa{tJME$)c_dCwo0 zwO?~921lK7=jh#CcrHZRtiFbq95!|M>*mG8ykPrmM?F+bp_Szrs3 z8I$UZw9cOuXhyKobr)Himf#_l;eUb^1+I2u!m6Y^xeN%47hY|n@>_sa!p+fmoX6GBtmev`Yid2 zDdwh(2=gb{x*x>LPdy()>n;q3%VOzvng4@QhoYk zaq~@{OKiW~>EtcYF@dA6+_vHDpoqlfeKxBg6x#>ZYy2lbQxxdQpA^*2fwln+dgWep zqVybkKpwbqKrVDN$@}kIQQWf9YPZO~#PDj(p=?kbj^Wj@fGpXp!&{mGC!L3SGvMqs z;54+Io|LT59~r(fvw{~AZwQy0X3nidXE^Jv`^nRJ77T|nBcoH}-lCxph=z5b{f}tv_r7jpG1RiYh#Ze0)g%P*# z@w+B(Ug<-agu8r=HF*aw@c#WT+q34DA&-LIJKh5ik9E&D6_;f7v^Ay%TNK%4vA8mzzJEI>Vhg?)8N92% z!YOB7_|lu+E&5#FxFvV2sn2T3K-CZ2GCF>EKsVgs6qz|w>=&|=yYs!>`9iBf=wAYo zK|>@wEuo*zZN3i0BXCS27k36k@|{&cN@cMsd}p&@$+r2M8v}>}FQxtcMElb*xX+rr zSy6r2fZCK1wV)eSCD1Ey&e(Bg4N)N@Xhy=T8dRv)B-g649bifYCOP+ERMydl%4nS_ zv5a!#Z8o_FWk^boY`glqszO;J=@F+Fz6uofP$NxJbO5N_rMtKU7um#JD74V4b5W^) zSQTN7p_<4l!FVI=X0 zn_F%F0q{siaz2f%B*3SD5j0m$N&+#Uv2}D4xh~*mNHMUW?;Bn&;r-X$msn#S-{Dv7 z+;O=Jjd^7MEf25g-asv?^qxG_qsroL=i2t~ul(bZraU_@4(gq%>KpQK4TpeAjsF-W zlYz*(Bp|F^QkXj0fKc*$zTkB5eTKtW|Yp5|v$cC*;W!^JiJ;LZu2fW(O|B$lOG^=N8KljzJOzeU2aC z7a76l!G6y*w6PF>6DFU1kb_5%<17nuSoITk*_9+C)4Ass@AzBnqU8Gi@k>L6jleU0em^j7J1*Np}su1B0Y6+z)99%`0& zor0w>Ar95)FXC;EaUVK18iFDxETn*ROGDCqF)jjY2IqujtMQxrH;ar86P3!n)NEdU zfo2zuAMaZdFX=t_HN;Ckh_rT?0)mzQKot_NSR|?PnaamaW(W%t=c3*D9jlnLL(^b`#LF=ZDh z{*M`#(6saf1wr`_sR|MsdNzO>>()a8uCrrk0NsTQCLps7i z4i`d8dhatr1G)Jy_BY{UfH0--JpidXUwx=)VP61(5FntA^j1=r@OG;bXhHcfyN%Q% zsY)_?Sipm2qKHze@L9~2_&^4;W%pd}(5TP;a?R$c&pvw1PvJN^^_u7H=rvyxE<+c# zU)xpwns)oUU~ZuC3+&h2kczTjXjxYZ>WN1RRBh^e1#31$Z? zzk|220$fSba0tH_LHA2N*rk_)5r5u_{CVi) zllyDNgNq4Y6~SE+8I?Cm_>YlP%>zL{9F9Q}=bi=OA62yd2qImd@Nm^01L0pu;FGh= zqO@Nl7nF@Z%v?}?{1j@KaB=56j!p<9viqq_^#B-{Oi^?F{#veUCwWQbG=lYD8#g+5 zhDrPJyer?nV&>3@B1{_DL52(?d>IzwAXHC_u1eE6PCn%16yjqSn3BDrE)N`KLJr!pe~pr%ok;i zci5t^JeKJv$cc!04vC}OQV%I1AO9Y9i^eNEpLh)g!*o0{jeJEe2Ztz`oDIrfeK`3!w|QA=3Me zeyY$zTiD-k1-jAZ4bP|9v)(kyh39+lcRZcm;r9zXIB&qHm#5uiD);!j;5SJ%NjWCm zn0H#|<}r0k`u52kH^(%yDth{6PrY)Vq6z4GyYA$=&V=GtdnWReJ2MK-X1ZqY94dC( z(K5>t%(oBF2Wvv^zpyhl6rDXY)01=ain2>_@Maq0|0@v7Bg*M-M>ORhcfQoN5kD&K~oJLjK!=!H@?MN<`G_ z*O+^mLJwwnMh4l~c6OXmZ^uHy;x$Zo z=+9Ixi)RR(Gt_|rynJojmcJ)np8o}e&)Y!^2r)xXvz7u3;RtgrWLj&V&^67^LQ2f4 z*ZV0m!v%T{IW;IUP7uDi9l=<@f7Yh(ldX;55h|%`EWXsNDU>mmK7I^eKn=j1xJ_z9 zTLxQ$j#^}z-@rTVxP3|FfA?j4!hyMYC10ncnvZ?Vd;8 z$Euh~Wa796MHE?AlagMLQae?|;M181EM&yLYMNT7BYvv?BE4Se!u#_F%Gdeums!CEZABl>hb@H4XZ|nA2WQ*i+ zg(AVQ-HKZw{600PqC5`6p>lgPQ0R%K`&`z1SF~lE8j2Z5C_qJBr7S(t5N^24sJL|e z3>`YvB_698FDz^*lC%pR@p43~ib1L*ZS2q~W95i4_)nA3T){L`%7Ap$eWTMrwEXD% zj0RSTXkf_6LrhLyWIT74)x~kR60reCSS?h+LcE0tcztn{VJfkN83z#D<^T>$YH^As zya>#42%+%v_`UwL;_VpQha2a7=$^c1;vr&(YISJ$zI&%}Z!r_epTkthgj6L;SEt{d zTihYF>@G7|3U4&$CxIHUSh<@KpFQD{&Q1JCbzi{E4>zM9`5lPBuWtPZNwdWj#Wb5+ zg)y6z`<}(-s(jSWm0UJUC255f#;xX`wAyX*Z~4l{tyE7>I^zrgsT1LgDN*&!_1Hv} z2BaU-@1cF7YYO^p<1_DBgnqUW^p!uNW8OGS4ZeYeZlK{fW`~neMZ>l6fU1(^K8GoQ zWpn{SE$%z(bzl{}q@tiFev3l_XR1d%DXCp`@D}w6#3suTdfm$&rj?+UsF?$G>a@hR zlsi`!kSmkS&NW9yJH{Ms5a1t3wS+Aw(lAMhRI-TOWI?C4^rEx0=m&)Jo)d@rpY|v% z_|fPW2&}w>VTBC3HFa32N`pl@=dX#?UIQ|qB3Q4+qoVp(lX?UH>y_g*Eef3cYJLQ* zTP(O&6V@Q%q^6{5^)uD-8U0^;ez%Fe-X*8qp^%en!|jkKt#EP7mG8y}S5CIvdW#?m zcFQrl%&q>YhCHQakB7ORpdXS2*SYj`Y#4}tj{BA!Z6$C><>fH=br|Se!hKk%XbR(m zpwOU!T7QN)PNg%t#i*Cgkkxo?=?px0BAT$MbOv9Aru{iF<(6Xwt6&k`o9^9AeLbjS zOnUBE5k2Wd*X%vp(^O48(7zH^C~qlzcVLBv5*llBFR1o6JqJcTO`h@nCH=5j&;Bty zuG-)IH&AN5oTt02rfhv(rCwV~?JZ$BUjdzP@&$DJGoxD^&s%_E)C{v=1Hi1|nXDoz z<}=W)$Go^%aC9;})v|MwKM68k#$((P&ScAGIwwc*8aiC2$**y_58U!v5+o00WB%Y@ zS49f8kQ=wJUcjW-z%15CPHC0hmn)fhD-hzYPz;UiyYqOWt)yFg>zeTh8&D>zt13k+ z4|B)ad=Kkp7!zJXNuRR1Ye{C*&sKu~IH>O5+lXV&5`*51b+S+LZM3CzmSx85!eqvz zI57>wx5X zvR11_YTgfp8td0s)d@6XY}fwXF5CFgRU;cPp(U2vz-=~2Oj4Uzt_H#WxheopRL4k; zW4R;%j{%w+Etk0qZrJ+UfnX*JDK8z}I=U%svyC5FH8h=Tw&2L{H0G#E#YKzfN$(3Y zm@Z3|(X?|Hm0&K^M_+>p?l7iWe^~K!tlB@0WxCD5Xd&f@fuT9-2NRv%zsp7F?;O$5 zKSDrs@4IJh3JKtC9<#ZyYaO!>Ubuh^o!r6(0FT+3zIO6%WB0kRSsY} z`ps1x9i86050p8w>R*AZ%$rG3bC-v8+zeOo{}!gQU$}2GC<9{^N}DkV*-Wrl>2SBm z4tibcr=Z2=fc0Fitk4~r<}bfc9)$xIkS`Wfp``Kx!HaPpFsi~jYcxm}GW z)q2v3F8PhgY`=|rIeLWJV9~vdw>IX}O@6atIc>2D_R&-F*^^QxE1tN$ZB5=Pi{_}W zt-}n9Rkn$xqAw!io4Khr2n;8{8v%IC9YQ_zA_MzrD`Z#!Jo!W7f2`Wl0=wFB+Gatc z-9({m<6Z_E%Lc3Z<(xHLNEF?oV!IVkN!gK`#x9<6qM=CiFXebgIbebM3;5bPMP^Ey z+d8~K3ANOL-p=^#C)^#L6SqTm;DiZvmIFTDL6$OmzP1aS(S{7)dLPp;E^LgGP?biq zzt#<`=IqoV+@J@;J}6|kqVz~tiJi#mz4eqV{7(69FsmJ5S?ac@+!IV~>K&O5sO%O+ ze78f1G`9`OolH*i@RHC~ub)&xKkKr0K9LzXG>XHfn*3AhrSntlVFXlAFS7|0aO-iP zLySl31*O#GPF*L^R*MF4SKdm@3T|eh7RJ?YJ-GRB4)=bFZrp~o@o+QRxrna0D+9%n zY9ezDJzDJaA^sWWb?I*OTPlw{W5XTP$2#zo%O1YhtXf{VH8htgNMcBnUt;c>ZQG1v z?j-lXX_D#hf^QeCT0RodPVAD}e)dr*I5C91JP*d^xV zRKB=E?l9t26&C2S>xA3Tli(f1ql zMjl}~w&**w>f?iZ#~Z;8sKMuh;M`>t4BK_})sIVqI5~jv5X__V;L_FG4sB;*Y{hi0 z335F*{T2o`f;sDq4*-U>d#pTq6Ui|q!TyCc5nw-H3;!zweiS5LK@Ru8acfKlJW81RmDe1ET5wO z{MyZRqTFqXCSnrxvyx(osHM9MrbeR}{v5Ec$M8^SQ>r-}IX6+k2q7Z-N?Yyk9SXmL z)f3!`Gw}mGe-msSXwI^OkxnI)3%o;ON8!IDh$vc8EtN~SKcvtTQf)IfHBqR1hk1m* zfB{KiBh|Q&pgzHzF&F?ks|v_}BaZY>6vnhF@4>GEkoeR;{|^L~7J{F*Kie1+^|yX8 zi!m)zZL>%lf)$t%!BjK(QP&AKy$)L}^o|JD*Yw;2Pgvb0^@WOh?AZpOU?GWE95o$K zjT+c;IhU*Q4bih|pI$$r#L<?gYOgnAZsU3htoj19AOCZG|2S+A%L}!Wj9x43>K8BgXj8a{pw4B zPiBh80KyXnPFX}7*vaT9*})r4+-&_;hCxwH-xiZ%x;fZzQ~5mQazmpj2LbLOF^*Y8jFLY%7y?ULE}==&-PA?npnAkyD>no zK183Wt8COTu>@RJ!%l}*JBoNc61!oEY~;cYE^?bq;X41X=upm}%YWrtIdCovqK|W* zH<^7nB=&i(OIBoyC{>z1z@p71eF6l%-U=IDGVN=yR=x;Q#epV@7OBQHmGvr#SwPtH z*m6}7v0V6w%E0Q#_7*_+%+aJp1bo`S63?0{-2wPm_hx1VKO;a@!>uZbISL7+<6BC* z_js!Dt%N0&?;IB!4Xcylxj%s`(hkQ10*n1dD9-J^X*Y{^J)BJkBX6z7yJl78C-fOV zbf1YDoWnZ;W(^;TTIY(?Iv3Bsz*c-ai}Rmlm=Ck2xkyX{^LuNUuOWG%h~*g<%AF@c zkpz2wu{DG6O&+FGg5r2{z61v8YMH1t1bd<`j>n>EuT#{m23LbwZNAl)Rio3Sw&GXG;Y3DK!UI=k@hl^av~MMAig zgIy#fnoh8bghp_Y&>CloE)wd5M+6L1KE+8k{URZ|av7$Oev!~Nf5&Y?tdz9~xJbw> zsBv!YElRY>*Oah6_iKdOd;LYaMQCYCG2CzoXrj7I>iTC~h5^}Z)E|KU`YuZ%MXFmr z6ag@@Z3qQbFUa7wZMY@xz}Zpv_Pg{88L&`pB??}x)f*XXcVMZ;Z5YUu;tqzG#Jl=V zZIZmWeqmts#c5oJ!JD{PTg2{=WV6Dq!>D|iPqc?Z?TH%Cg2tTAv!}T2HQIMmmv-)U z#uKNEJgJ^xt8d_77Py_+vdIpBZDFZ{}@5S%`FI@>>OHU|Z^(>(v znJ()s&5Uuv)_uk*^(YH{|CLN4=;OCHJi@S|NABtSFEGCUW;U*eMQQvYeVj|Paif>jrJl;rt3c3cjkkP z_j&!eie-Z$b9VV8m(Qx!?zM&3AkI~B4x6vrpK1$sW{-j0>@E+!f*>*{=aM(~6bE8< z1re~_nkY!tXxyE23V4U}sN2Q^j&1XQZulPmD>#T0rR#R;hCl976w|lTd8h4kzQl~i z1fQm-s{^tfe>6A$CvFyhI zs3cMuRl6LkP5z>~$=O1ylRG!!SPq-K-=&(oCd~iF+WcGi7d7~p1;eJt9|Gv=>}ihc zT@R7F)9-AIM6{S#*gnBMgyvxZ(O-E{D(ArbVD--VKXamRCy4iH5JfcQ{)PG}H)C~M zgbSuD_ZfZk^Bou+sQkWRo-xKJ*=YXjv{~jVzb8!KyPwiWe@}A6iuX1Nd$F$GYtbs` zwHDBT2pv$u2bC9OP5^17&RG}%S08!m@c%Ze9X-r_YQM!L$ri8QYRfmuA$yzbkeqHJ z&fSbS_{o3PE(aSMd61a5T2-%N4`mw#glKpdF5n~yM{7F($_-zKb~g$k*NX%2IfuMm zmYwNH6m@EVi~%aSC0X(jpcw$#Dmz7|n-SrQiVZAqQ#`GK1pMa!Z8l5L3Nk^f#B!NB zXf42Fhwva=juos3k7`tEc%wUk5dg@MxyV8=b+|*yb_p{lERJkQ4%myT&zkl+<2j{I z+tAt6+0|hWJ5m&X7zG=BF!y9?DdwA=7a^@M#00Cf4A74VF})4Q2fd3uEdXBSe*ZpaESZA z6v||PlalKp-h__RFI%J=m%*11Q9X=l+4aoaP5T~L6Y!Yqj&W5qS?#-a{Zr3GT5;gx z7F88|qG|n0ZW22V&lI*a$+8&49jBpIUr#~Jq~nb%91g)PXzC7k&b$369rYt9zQetN z5-d6t*8rjK6YPxIE(gUC73B6GdSG?4*=&W9s|cCqr`~cL8_u#d>E$-mwF# z#r~s{Q#%nN2@5tg)aL8Wm&b-9k?q+gC-|_XH`{{iY3CmY5w~*}^*c56>5Sb;v+9D4 zwx}qYwV0G|49$jHP@Wkp?Fjofig;1Jv^Nsj+nvM5TxWNq{>p~OxpyO}P91d^1Jjl- z(LN`95}s+}n=H5kL&~HC!713a>4fApoA>S&W$8}UmTR(w)b%ch$sr|=_&QyCksbiP zGDJ1Vt}jCJNTwKd=40cHghz~{F^)ctQ_S;NTPv*%<6mZyD)tpC8*L`=Fp5+)Bw*}e zGrgno_C@bbRo`8C>!NpKTz_}vJ&WF*V(6}7q}K70 zUiAK-)!v`3f4`vB-k&z!-&}b){{{{nLOD1Oz;C?a2bEu8-sZ}i_@}r(V*GJq{9Tpb zGWc(Sc>65If62yUoT*`yjo-t+m-{rve`Sn!;f%Q%?_uvpW3iR!K)Ac%IHCkN|JGeX zP~Q(NxWN5FcdAuLXAM)7z5u^jsHqY&%m^jI!Ch zNtJRoWTp+=BOBa|v*CLhPEc`K9oB?8tWioSheAgkPrh`HVG)Xi8T8j+k<;;Hps9*Q zLfaB7){r=I?Fcs0@MQzq z%vsTXHfJ{F&2}+kHfL=Ujb>8@w;wm!Y>i6gO)cw>tz31_@hRI5-{927mf}b%a%+^^ z+I(ShG9GD zIWfU=pe?eKP+~-}1_z2yCP?cTimZ%OB(x>+lHh+&bpt^4@rYCRhtZcc5Sm`Uc{W?8zdsz2eKp^!^w&J`UIS0v)LJ7#ST{k{otdn|L?8E)r*X1|f^nu*)%IOmKw$3&EUD$9ryWI{MR^BtHgO{iM zM&Nm~q0-R((R|qcdABPPc019AE!4HH#g|C>?2c_V2NUiP%KT#x)+F>rQ*_&xsv@8N z3PyF2A8j}Y<-t^zAoK6TxGwUe4ZG$a)yMhw@}z8aksoc?KmUH+^x;E%&M3R98VTeO zz~&&^i#Y`l-Vi%6o{TT)H)C51ns>EL2?cITMikdQHcnZk`fYm?Iak-gDY0vNZ=Alo}O~>t}StGAx}s6U9ffGN(?rebPTa zu!FPv#_aY)U>o$0xW-~~OgnwzE_W;w)ndiHN!!M?;)#8Jr^BWO{2p&u_Gq8-gwRsc z=KN(xJ9%HtgB|2+!Rq5f=uDO6{!2&fWe6QM`Y``r82ug7jnRhJp|YQw|I)mPo8Zn+ zB(~0&VxStvDKn^9jv zD<2x({qjx5yC227n-;x$!BC@2FWWRg5a9u=$Y$~HnYBwE!RDFNR1qEK!`YDA5o_$T z@R`YDQ~Heiwxp+$+ng?w%VcrNCxa0M7;xD84oo+LE!e8~S*-RC`f71g&Q@dmQ8xZZ zWBfa{@eTaH)V`ly^nDuFzn`AR_d)0Ue6#5j+-n+c(k*LLy40E0qR)@wRxC4HwePXe zs$0rp?TjI+CM(_3PF95Bg)v8f8N@nDxb-`qkK1H5i%T1FNfP4Vo3{3@FNk*8Y*V+| z?Yvc$^ZI(H~%*i-sVUbFER~EMhY(wp_E{~;qn}R=tgSoM7AO>#Z@>wHN``3}fEdrxf%s z_J{74FdpG1cib};aEmV6h$c!lb<^DT9V#wKvu^`3ED8=fCG#=WK8wAS%f@ASmsQQR zyS4c6T+lUr3=+ z4F)FDg|+x;u_Y7Hq#Zye+W~xJV3ttF>?9a}^+lZ!@k`G^6106eWb z+i=Kk4EUPch0Sb;3Pvn0U)baiZEDtHos9%_y3iC>ZL@Z@F`Gg##Uog4n?W|GD0S{0 zX`KtG#V$*-r6mraQ|*%gdQHBmSYSY}&F34_R<}H>X@bXOv#*VG`^WZn#xtQfwRmKk zk^ek4=~cF=)BJ1aH(;DGB>zQ>SB&vD&d)NP0Wz`gqaF=^W>DS{#lsH(GxxjcfXMZR8}oY>8}E?IxGi>1;WB|JeBUmWh|19N0SC z<`UaC9OoYT!1(HNOJT#*mz&og>}}doa68Q|vqO#b1zRSXc5Vo?mm9;94{6omSd+Hn z%1H0_(#+{W(dv}DcC5;BXL9Lyj?b=yorX1;S7J?eFzaT6UCDx{EoXl2OEf1t*7OGt zI^xZ7?J3uDU9PAETrZHUCa}h1&vE6<6cXOfeHgj+5w>pTxX`j;#WC?ivYUkuX?yxm zm&E9Xe!<28N+zInu_Qb=wl{-S=EK@ko2{_T(v3C*FzihQu7OC^vUPp@Wb^q4#zD!c z2M_(zik%_PoEVH4i;--XRhyE{jYc9pxfW+*V;pw@;PPnG-uqYg?(72TGHvZf#6y?@ z%%ufI`YfR2ZWyu~0|;A-Z3+Hu*eYgSj|%Pc|3@D;uVmv0;$v$?^>JoEzny<8zAx$H z+)HugsczOyv2n}7IM_1-8|Dj$hI?=k7ou0Nr6{)3)m68xPSN9b2>nC2#g71Q8QAE*Zzuj)%d1X{b^jmf0Hx5nln@KuW zejjU2rJ7?6CW1w111!{6yOoZrQ!K5_PnzBpBE%7wrw%h{TzKY=%=TzYJ z*FkKz-L7cYLvs_*9M^p;bc3%a`3*xT-Uv)L1_*fA;63oF-QdaW{NL&0#0MBx>&L68 z#yAo_#Pbb5r|+|IEC}O{g>l$Pp2`C#R%<~l3hpt2+9i~A94<@` zH5Rvzygd}EJh1BG#=d=Pyv~6&xm5?tP&W?yPM3mCgT=Hj?X_yS^+&x;a|!_&x2PsE z_PYp&J$cJ5}+(YfMMoZb?Y`USvllfA*FzfHZ4l> zvw#}D&yDSP(KN^PpP8E*-QIHe=KmeG+YfiljK*5_uDTT^Hcm(Bw(k4RWHyXW^bB&2 zVpDV=eKt{S8!hc|RPOCRy?ONbfv)ZOsa2_!?ZLA)J9mMTRnNrGe!Jg2hXNA6cXA}N zcDiXxy5v#3cEz?ooOVl&i*dsteksD1?Nq{9b$kfb0DlSSwa_?qa)2h!;9F4kv=p<1 z2yBQe%AK2Qq9`d01c}0ec zBckxXUG7Y9=;(0c+7#N8`_S~lGZ^Y9$9o$c`RHL>ZKQIt>sZ%KhXzFjkpz3I(%74y zI@ImZOitT&x5aF=wWRzRA8*Ee>FOyv+B-@Xy0C%qvJeN4d%@#y;!jX50Am&Y#~4L6 zkw(uvZtRDb@}I;ga-3|RT%P|YV?4@#1LFZ>{K))w@fONnJRIaqg$=J*dtiXvU1U;O*b9y**w3cHwC4?Pl%Z+ydE-j2U6^ruMsJ;MMT;|sy4qng2e)tjKzhs>NOkWS8raqmOZuBT6KHSSw|<~2 z7HaKTKftNk##|!NoD!q`Tly2TZBDDnZ(mI97t*5Kw{svIdbD~_mx z>)AKdzpW!4^Q77fl9K6PSMG=hoBOtWvoQlVxj8GkaR!MKcvn+%ZG&OxJPV$XZkz>fkmB=qBL$SHgQgley8#Y0q0Oe% z)!aAWyp|*TkIbg)Int_$hi`-dn~;(7BfFMlxpiGz))>&pqz>^pG)YLinMh`1*f-ct zxB^uVyuuIT?z{Q*Tm2CJ?m_f%Rn?0pTGsCAa`8tvXY0nhcKoL_nh&O3#dz~NhvM1Q z+r6$3>0aN7&GfA`4;{)KXhK-iVRpF_{o$RvV?zg5^J7> zp1fmE3DA3-C8umrwSlAK`QlhdQl1{$*A?lW>0Gt1B+O~CEo%4N*>(SGw=z%&CS9eg zO&iWlXAc&z)ikr_POOLw&NewBSzp`MzNVR#nUS+I@Thurj5Ts^;06cX5l1`>`O0w4 ze-IK4aXZM}1b6fNXW2Lw#J>dN$ZE6k+vfkWCU^g>CK(fpB;)3qWK2LZGLa(WVCLoM zF0kct<77yp9TFwTuP@^G>byi*X(a@Hdcq*9viwE zcHG$NC@e^UAL4=>RKSfc^`2v|*@&2+!#3Yik|M6wP&_OX$8Me@%dh(d3;;l)_0pN>OR#a-SgW}!ePcg z%AwXwQz@uhOx*VbiLR4f29O?tL?Vd~NLb{bAoz185%hjRbEppPoLwUjzV)WkXkz8D zRWxxl=m@L#TLXb30gw1vm=Df;!dgQ-M5uEny0Aeh_@f-SW=ZiIS9O>G|d-y(mC*Y zY8%{eG^%FC5`D_8-hS6Amu7Wnqb#G8Uftu_wAC)}RcyJLi?d%}d+)}=mW)?5xy+gx z?+p|u3kUY`ENgJ}qwAk{kj@h}&F66=Drvf>pS6BkQgphWWA$Y#x7<1Ea7k`Q*(sas zw%lZgr+vD}KnS#FAVwwwj!kDr|84qtbGePpF3qHwkk9E0wy(}KZC=5zVTw7QD^QNZ z;n{Ga&yf3j01``OQV5sX5fqzXRjk$NS*2NL8s%(ImB>!)2nXj#$hVZa&qpGau1vEV zPqkXJCmVi@cfyg?bqO4YMaBtqM?8yrh*8w*E$yWDxQYet^9;W3vBRrV5LpA25Ai3t zN6>Hwp6pzT{$4LiX0Z_nUl95c3)}5uF{(OcZ{ZDfnTSyO^MW? zC)Zi|P=M>(yu-TjmiF?2(Tyh>gDyFqt^7W~eLWLNHTCz|ZJ4vS@)-X)?sYit34L6f z6Yghy;#uXFn|#LK-{qd#+cCK#XbUw#rne78oH%VT6b<;llWNSzll|^&d*v}dSD4*w zo!Q^YaWm`EtN=LK6w6s$4oe_a`IDdfSUQ|+D)-sZ{2F5XzxdmbUCQfyx^>lWWXG!5 zs0R)9yRRB&A?J)63$?a(#$C-tzZP=@gO23H+Du{Xkk1}WqmnZ-81&EOg9*-?_PH7x z{h4CYZgqxSz6f!Ml1PlMiAN?@rZV&x%@tCwm!*5zu0uXxx{bTAS2GR=u_}tFf z2l2OA3adUW@($h%6$>2aw6Tpk_~#{pKcveq5()ToU#Ahc{7(7 zSl`mJrW}KR@Aan(TxTYj_csft_LcTb6`Ce@bgbFe`j^RMb2(BBCP)C}kj~h}7vRPc zb73_s*ux^fW&Fe{eI%pUZ}@>jRy^XSXN94=FmdIdG%>{!|7GIb6BKI>CV{|o4 z6BK$35#BUSOM(G94eZ^iJ0v)YlhYHJ8QP`zl9%%Hz(cy5*n|`|8cqX3AGfjZ@W$5E zXwmAh&8iM-TbV0$#S*ykA>~&;fg$qz_&XA96Hn%5 z@7+1}qC4AVtJPB2Qfiy^xp-MVtGdGezIfAA%YV7fYmT>`O!yjOuXE)R>469rn%>p5 zla6rFmmiH- zY*Z-Bc#$fdc$5*4o82%l|0#?!9>S62EWg$m|2n#5;Kbm(#C@N87kF2XA2DK;X(NN6 z2+7yN2%y^1u*kI6>kZztVRKYGJO1LMpOD6Kp_Hp7!J;6$%ZP%6d)9Z194J4j1?M~t zuJ_DV;h}%n&iz&IHDQkpD>K9ADD07%M;8X@ofNS;tAS$tjRwaHagJ)3gTU*m!FLdQ zGI(h97U$gPp3ZRhx{jM}lZG|)m3`%<13Tq@gfyI8e{ck6-Hu{=>*n63nH8CP&I8q# z&T}sv9B@Uoc!)_#po9Me(6oV}3H{CHFR^jJ#lI8d8;$Y4`9n-1P6;t&F_F|TtfwAq z3Eh1VNg)}`j>v<)Vdx+&+TY_N(ZvRvd30IlLlX8c8}F{%AN<0KbZgwYaKnd|zLPtwiO&&UtlrPIlA~D%zU*+O09#3Z7z}VQ7$AuilAGKIZHWN*+Iymy%w%Nmdoku$m zGzf@pM{YFLJe~`M94`NDe(lakuPYntTvuXIq{=;nSKxaS!*{abm-E{|ho;I#f)e8> zI{? zZ74rkd(i7xHzm5Hc9E0XC70NSqs2Q#r__Px4#^?nx5x~@o^6rHwp5D;OqK0wFMJB) z^!;`Tf9j?`uYUy0-=1%6_yhM&)Ri|cq>+eWm=>d=F0!^z4K7O01TX};RL%;VViHt& z+Tj#TR@_w8ervW4?sf*Z%YfSnU^oc@smsysQn)|hM)Og@scLPVo=ulWJ`G?y=x+hL zkw~IskX*{0#|D3&FEQb>2*A{r5M>tyWw~ z9+Z@>qTO$?DN4}h_B1CFip75NIqV$n)x1TDp*YQA32OP0`2VPT4>-rJ@@`n?Ug>t- zt1e9+jb^0jeMZyE?(EKN@4a|;z3Z~}uD!O`y{&r#gNY%81VT#)Bq2C&sHO)3gn%g@ zB#;CM1U}w45J-T4J(}?u32$7ufk>+m|WWmuHB( zIaPTOtO3{aYc7*;4Q}VZ<6MsGgZ$dzAY5a^t>eP=x!#6a3rGMv_Yk*J%P3{UsZVi4 z=p;qC*EFpAOmcHdVOe#+KZ}#tJK!KCiY`LjKw*5lMt77sfxaM0cx+>a2VEuUbV&7n zcjrg`Fi~9`%>02Nsx2yx?ATP_8cm-+&H)^rTccdZ;ik9qo?&Gvj zBf~|;A-W(b2#w%~&nmv7XHS2PU(>G8v~UYt;+8#w{^0i8_n!C^nxKvOee!1#f@$0q z_QbS6apQ(Ac8oinEwv4_|Eg#x-O`)zokR8?wT!6Poy=fLZJ5$0mN%tcK3~avQ#$nr zXmYZ_=a=79$duS$qq-pI_J%S?Fr{6SYz(e#t_UyKM5jh*^9D8Se#hb~B79E@o_ilO@6p zL)(+UkzQN2o!c0Iom(5qb}7mvAto-$@I{PO+|s4 z)`UVESCpoawz_bnxwodSztT!prY92Z`>*ex)2_8DVnsz}aLY*Zp5f}mfgS0-FyF)y zZre35JXR8_j+kM;Vm7Sr95~opg40Q|G;g5@ubq2)+@_)pc(xJfaTLZ9xj^WJZPzYI z?XdLPWhPBNIBTQBd~ESGm{|Cc(vAbhm4I?!DO}>Qmm};(Xt^AznNimP_#d+t#B$f< zk09Q>EH0m3U(iGA%N&zJa+i#ML8&v~%lvFf%LS-txj|Vt0qe69Z#reBbOwEs;U%pf ze&SKL1Sw%+{o^=y9y=+{@b%{KnVPYDzW%u)Mz*od)h6+uDaOCG-$ z6-WpJq`eWZ4o{P@Aar32+&kHr1KYqKMT{ z3|9s&Z-5+Ou`%ZeSAWNYRzNRgzR6u)vKO0CEwjsYHAKs_i%wG^jKGj%Ug( zlGGykm1eW0g+kK^N#oJD+mVyf6vSmUOR=tH8(Q!#Y-kPQ6x$Q7TbB&4RdPU<1isAv zJga;O?#Ys%DLk_h=S6l^Wxk11*-U_!4(=FqUFACKx<6~DWo-%B>2pFhn?s%S5m9G; z_n7R*$(n5KS~mNX4U{COQ{oHyH|(esh65sZNg=5t=wp8g+5(ADzC!`ow#d-@eoq^y z)Z@RI><%I{00Q(k`A19keb`+vCE)IGUozmE>{SEdvkS)YjRlG2 zTnQja2Y`QOn5M>-8ia?r@KP1Fg-jN2`B5F7Da(uMu=b{;DEjPfQwZx^dDYW)SclzJ zhxRkrv@g|3_-A(V7YlEhRPQlS50H{9^xr}6om>P6^{G;*zzEPl9e!Sm_B|4w>1nK^ z-aZ(}mZWuU>0;t%7TQ3@83dqGC=>KVCck(6ZsE^{5@nxL1J$uqcM z?u==^fiQe}b5WpnpgBRCtrDGEyBoscw*J(N5EFYpiD=0$HOWeoWbJ8{$jYU7hur1~ zJk5!n5`QG1S0NnrSQFT)S(ck6pVB0=`*~`OvWr=R9+|e>C7LObM@K|!p}xch`D?P$ zBCDV-Phu9})vYdJFTv?s3&JndAzUlIAT(X#d_ia;zId(ctywf>X?iX+t(sZAWZtgOoK<>byLa=n(6?t-^K-Y|YMPkV7 z;2DS%Q)s^(r}(zRtj05OKPXQkuUL3a6y7T(Yy}$x)86YMK$s3qlJ&IQ{LdmV$y6=R z-&zzzV=Hm7>>%Qk!q<=)BP+Gg;0uaU=Sju}7Xfy@SwA~j`|)OM?wq#jPo1u?t@EsN(kwRR@dP_^y~0;GKk@7UKPL;W&0M^c%bVq;2lC1q zmlnYmJ|rRE3Ck7YDX-sQKDs0DqMmMzB*J|sMWo?L`={}V#Xoj7W6`SEh&XX z2>F#u)htHnlmEFw%e#=eiADLqzt+|^#R?E_Auh3#ImkY|Qt6yUS*0L*d3Bg%X%_P8 zvI?PKTHbGjUA!oxz;GzU!&$JLcXbuR%RgS*1kqxw@|{;GVU)G>{vGY*O0X?u6EYPj z2(*M15Dgj(`>b@7N2=H6}q4(1*Iua(%c9}fr8KKfN4BA zR-h3q93=5#(IZ=Z=JTYJ@l>jI2{|em_ONB)t}>}D#T-U@f}6uxAoao{IO@7-NnlzX z+qiJ3Wy+UlCNBYq!z(eEk&~c;D&gOelOV$Db)7<1;_fU=v*9bbhU?HmDRE`>R}0T%f#kK97YJ!GLd*bT=R^_4dV(RH8eRat(7+2**3KsT|#8<5~+t~>S zVmtDmZgV~2`aO=(Ld^355)iA%d#mbA70z{Q=vgg=_Xtn6E=r=tj*j$vXTiybnpq5I zSCCFKtgW>jlWP^V*8G_V996YonC^kqS7?Rg9v+;@ZL`CAtFQDZifp>yhjULXv^gjH zY?kcwEMC%w93QGi_%SJVT^wzTS@^sZx9qrI_Kp&HGBVHB&F$!&;O;-Py>92pcQ%f# z+upUaHWH(4*1~(*aRN+FO;O4;%s{%L`-=X&17PmpW|eKZ!OD71>#l2h+s?K76uV$# z1GWq$i|jqw{2-RQ;>~47ldmR1TeI1R=01^yn`5T?S2*Ry!tR>uVIM3LTpU`0Q$L$qt@by+Lb-o^3S1;Cj-b|(kSug!Dh&W~ms%!4Dyu zE{E6&A=kK`a=j(r*0OCYnahi5l-S<$G|CD?$%+|5D9+&sWlc=}D}c)`I<<>X*cRbZvSE5lUt z@8TD}x3=t5$o~I~wI)18HWU;HkV5+uZg9QM^(U9B5Wv3>+c#K{VqP(0&DJz8-@oMc z3tWe=7KA#K04ICfGrQpu#e{LHM2~6=;sRnVhIM2Z7q@k)Pr#J z4TY|L#YDI;I95zr3qfbO_6+22o;`DTX6SD2utZ_itV=bu7qedeav?>ybjy1YW98A+ zAw=6+v@P)pkJ;hc$)>z69fu`e>8IDEPjJ^d7l!U7z-iTi|8`pOX z9_T5tyBA9L0C4CQv@*agNL8x`zGP|MvFrO|vGGLX&gd$_@3JG>`BCR{Lk|Ip%q32C zR5tWXzW$ic9xi;di*lEHOj4LA;fqW?96) z>IhmIZ>&0omclx`si^x2-X~`>d`nb_AdTo?$Tq&#Qkj2#M!17LyE>|!eSBt^BjZ_B zUC&|WadVjMK<{|yx~0QxK}ua*`4<4VWtaj50&ZEh0p-;;Nh;sm{>CMQH&-GKX77b{ zjLdno;QZBOb2jGhA6P9JT}b8F+`ao(QBvFZxrgHibsz;66D(x|)#aLWK_++wu(UKm zy+&wSin!*Rt01nwua}-S{gYF+3T?C}raoe08k`~_NTksJL zmm3aCGwj?ScKFMrZGCt1odJ2{A$@YL@LD=!kZ!C?!wVfwqk>3m` zb#B*=($em_248h`MUt`li6-|Ik8JEY(y`;FfuAp&>bJxHiQIw?&aotZIQY_+ghgW` zC=R8gx``R&V%3CW-EOoIL^rFC{it46g4eeCXr+M0=+qKVy z<4R{mSNP8E+!2eBj^$!@rhm=euxvcfc9b*nN)XRatn(!D0D$v176ZX*P{IQ6SUz1W z1e=u+id_ZLhnz3(S~_RJ2Dx|;&;=BSi1Uze^yYV`4JEIN)B zn2lXCR#?C;4y*+e6k_6LdRLtjXr~)wwFC8MfBSIHXNOlD2h)u3+d;=PH)KuEKSSZZ zV|q?&h5Ra|6+0E;i!%<8%G|PS+fzWFvi!YPlYg}uw&yei=^g?T41m!&c{5?O7|7Ou)E0u@>QUYTuv{4-+ID}R@GcM{&S;wj&o$H3oRAY(xvYKg9aFk+^4e= z`iVZt>Th=Cj$>QE>YphS){KT1GyKJdSAfPBG5*D4Yt90+^A~%kVf+kN!aId z(dU_6bAFzr&t0-R?)s~#)Pm1BVn2tEb1ZM1$~nfl{PVfTx%_*QfN}VyKvR6PD5JMN z;>L?MH_Ej_w)@M~bYp9&B;l~aa)EEKO{B_2Iz2ftZ@aDjNaPpQ@#645_g(GV{x*xIMF`49q>tE zZPOiUcg)i}1&jPlT|y2&VQK;Pu-C_!W@di+&qY<0wdGcM%|Lfoh0?jbBjQO`EwKJ?j#z z9smoWsujR-DO9%tcrJ-3$xF3mOcK4>3$;#`(wBWPVf4?Msw%~b-rZ~#DPF@U_J+dE zRdHQ4M^{FY>^QnuR2YgVtHr+hZpkg{aj#qQ_>E9N#@Q2ErRAP{a5V^%1CbMEl6poL zXyPpuhy_sRvS7IsvRpAtmqeVz@E62eg`aR2_2{ZGyuY&>LDERrACeq>f%X$@G0y(N zwsRZfrR7?{J2v}BwQncOz1kt&IDDkl?>G8yIk1A0G^(rF+cmFO%N#g&bHo>qj9=AF z2VMdYzi zsm_cRMXZKmf)_DlA19oobM{yv{bLGb$hoO!S%*hlMmH-y3t}$nv7tfKlXTt8X=hEK zu@DKZ2s(2T&+0*HZW7`tCmdLOHNv+|t~Ru_njQ)a>VqDu1W{&xs?=H9pdwES(p63i>|VdEi`c+u3%10jG){y%00G&J@*|Niw^l!Z~jj zb!oFt+NEH2VFhUdw;lMJ$>(eq5>=8!ZLYYV4Hr~&d2pPW2gjx3h-jQ=CTI4|U6i(? zF4Z%!y^M^`+PA{)2nFT%-(4_zo1)|jZ+{2uh`ltoQ&aX3DZLFl&`{{K7zn22 zYBpQ89Lsf4h-6x37;%}OtqOpIgEK9a$?%dO2HUm`ryiTIZK*x<0oM_n29)QkaO-v& zKyxb|+IX_6=I-MQE1St%R%-uFKDr>)>B}{TN&I!WFR-71@=g*YQLw*ShM~u9d`C1Y z(HZFJ>FW?(v&R?H!NaFF7X@kuniI0(GZUR#yBoscw*J%%JCU7jl_(VNp{_e^p1{*> z5~A_}sfGB_|ACdOToVC)2?2g$Z;2j06#DysFx5H)|Id!Bx5)Be=TQB+7} z!rVRCmS(>$hN!6*rWC|&9!2bK0}i6Ng0oT~_7@!5Whuc=z_g-#Ojir?F^10bF-=uf zy5gO@vp{{v{){p&x+*BMGB4iXbmpafDOxTYz9KMmx%R>=!d9vR4gJ*#Yq9y^lG(dF zv!D<#MOR`Qc$~P`qp%IS(3tzwbka0iKqePx%{$?d)r*H+rzr|g`?YwBWv`)^7@=?z zPy0>2aiz9_Tmbn!vRnhfj+Z?m{0yXMmzEdCjfLm(=M0(%^UL`^V-*o2^{o!uag|D@VQ_9%@P7{S6r;H18=!N z+phs2J4s&{fL6`S5B3Ee0EGtD; zZKua0X>r3Xxh*4z=JSH2R#@W8zh1eaMF$ciI%m@woypC;@q)Z>+u)zyX)NFbl3Y2_ zlIigW@GQA~$gNH$A3>jutY?W=X@N}Yis&_sXXnn*CDW8HopW@9(lg7V=4@2&*W4rB zSV#-&U||80Rg5?Scvc`Pze^8Af7*DxR4Nk zHCS+mPy@{P0ym&G&L5F%-SZFHz~ffX?|uQ=n(?_#jGtufCO z;$WP9#rQ^WxrE1sepd)6>v6eGVjH%YgtbSxu4ph4!s#7}cop=?kdTg|RSR9$pkE6W zsMB|3Y?out_zdwkZb9&=H~0);N@RkiX8f8ilo&N*>F&}hpSx5DXl$svI$^ns#ejBN z*Mt%^x!LCypiC97&oi0v$Rgfo_x0@CSaoBdr8RiJZhh(oU#dQMw_*CU`|Gw(phQ=g zx`HMwC57Mc(%lKxhI@3M&A7jVwepf(XMwrzZ*zTQs>a2pUdF;LEWFC)x|!BT%Sm@9 z6R3m9t__RhE5wp%F@7u|Q)@I1-lOY602dD)zNsNtm%tT1(k*S5ZhowH(9(A6X8ZZW zA2an`nl&|*9SJkY@ELD&y?W~3G2hJ8uh?6KQCAVF3<&V)V0UuX_#%c*p_EtRb0QoJ ziG&6w>lzc8R#8Et2Qhkb&yfUkv!MP$<3zRQ6~cnyRqEUP!J4WPwa?$V&eB+8ZF`Za zAJEN?bNe%2(yaDa2~I52u2#Hm(eNosQDs#?=s&g&b9Uw?B}Ggb1=8DGCuq*#YL~DZ zP@@PBhg*=~RwcW8-~U@M#lCG zWd2bz*arbG-E@GK9S9Qu0{H}P;uG*;0v9oXn5#Aiw3#@gnGnVDnPDb$&7Q^3!$95l zY&_~eJbb=3I7|qw1SJmP&5gPt;D&DMthR5E&!y}90nE$-b29L&T!AmT)VV4hv{kB{7#Bv9)&5~P8H!v}L9XuIJsLDhzN=A>o; zj`68q3XclI#1sg@=An`5Fo*>(00_=u36LL+Zi*l{R`lw#v30=Zl~~-U(bLyA?iD?f zU=&xIRk|0cTtWBxnp2y1gnSGXDwMxTd-!J7NvOztrN6hQS1T>k`i2$Bt$VlVK}pp+ zuh}k_$4ix)9t1|5nE@b%gZUDU`61VfEM;T)5__=b0SEJgczqGXRK~~qK1cme z@YC%a#%7Ac_&*57d#4@}O7OrKVjZ(Z5`mWB%uWN8Z+6J}?T2ry4IUPPpkiHMqYnMH zTz5FLpP-AmJCDTNL8qLb{$T1m7)k>_6=A5FJTV9`Q-hvavIt@bH4c>+0P;qAW^j|~ z@rYXM;A`zW`s+_z69>3G!QBs?urx@Sq255uPgBAB;hVSnV}WhA3}Y(JkeEuqnabNZ zYwwx*nGg~_3yBQWA8_z%BYf6WfbC$OoQ9Zw8X_+w2J}Qlx=z#7hK490697PZ4j+#N z%yoya=|1o-OtckKze+d6XuSa~bW#nty++M&TSI5e)DLQA?}goCXLod(>^W2aH$u}* zn6EQ0%s1rB_pzKPIt$SGT+umrp~luGSuXhQ!E?#rh!8L`pZ-VEA*U>jWI)?>hcaK+ zd=GxCZx9;c*FeVW@I=bzxJJ3!1${%D+U%9RK~GLHo6@4utcZI<=3n@l13DX6cf7_w z3UbT*%q9@+kviF|&K%Rcp3k}ckOGG1LjVpf6UgbjesAWhB;g=`pRegG&TO|xMw^V` z37d7&Vb06|1FV(EhqX<86*8aW1Ciw8qF=uoD}I-)WqY*s$B$Qx>ESAOFfl*SyU8DP(RjmW> z_*$;lykNJ^nvP;i-=UjjgU5zR?b*wrv9X+D2c^e2N{PcSVL3rE3-Y871dM=xshj{x z$Wny)AHTW?DAhBkuPOI3RS|x_2ok&CQNH~X&NqSYj|t>^n6 z?;6nJm0Dl#XZm{`k%9p+kx~b)5t_)<|DF1*@GvG)M2wlw3t6*Eq_%lt(lOP-K~Xnh zh4}Oz^^YagF0Rj@@ytCB?7ub67z{GyuAsk1Ftt6JC8W*9bxpt0NbG%U-BlZWMeHR- zaVv(E5g`&LAbnaeb`thGmdVd>16oq3c$&71vSJA0UjB~e5zP|CEx_Q@+bSDPy%JFQ z%H2Nw zbB9k?dPT_{+Ga&|#Q} z0qdBh?bS{8TDRg>b+0FLT(tKH=qpCxnCv$SSbV{jD$ttn!XSA!+bX@+nO$p25d+VmT?+SKYBGB0r*0@aYr zDb9~Wi2jHhz(tz%*9)mlNLFWhm^8!(R}>`B7&VRLb_PtElYG+o(%sQ-ERE@rmHv7g zmf9bZSpz+$26dLcC?_SI`Fit^{%)t}_v!Dd!59VhRj7 zZB#;_bfnTK@69JDc3szzLA@KeBs;Rl+HmUP@bO(&*LpWNw>kssM&1x@9;nt}a*(kp zhW!T~zKb<%ZDAsps=pq)erqioK0Crjq4Bie>^(eoL-o3*6NKDTyKWxD?Cn{860@)8 zvmX(@?7H@{`;vS6k<0IDLvCW;YOH@WPp)HK*h|! z80yrq+!Xmr5`>nN_@JhXhb7O@nV#g%8n5gwSBpDZQVp7N1*`&(p|eBLy5Q*cM8I^1 zwapPVT;5Tcd4pzPkb$X}gfqfbIAXvVg!qLFgQ#;tN1E61k%QKi!X7L865ax41c>7= zP2fWymeYb^Y|;Zl*hs{}rar1$!AOapd5rpo^06Fr;i{lQ2uqG_2Ab9jtT{ha-maIzn;yxEEtFslpd8 zjuwf6BH(8|x+TcIP+71dENY0-Oz0MwJ>ygVE$Hn3aRpp)yY?uBsdu!)@Qo1P0ko-3 zgoo^sb5=ZZypz?e+tb{*eW;qT{u6ygWlfzzd0RzgM`@=weQKopip}-)n~t_`J>B+1 zV_i*eWp!U=T_cd$4vP5?;WSYUEZh`vHC`YT!6qOYaFg7k zQD{T281f1UT?Z!GKdXIK> zo!;26W4P8`A(;9vqV-ie!VOw$s=O)I15W#)>eHJK4)!7_Z_HMu|uTFqh&x8F=-4To?#~SMz6h$y#wdfUAak9O=ClKIFsw1l` zc=gG@)eW}gO1&-?@2>QVs?uu6Zc&QHO3MACe#~lO>NgPBaaV*C4rY~uDeqH&Sz;!a z9r{B}*|JcM{BzA%!^EwlO$RqMG;T~)bem?kFBAncDhBrD6dCm+RjJXWUM#hr-h9n# zw>R#+W80R~?G?#n#jA=cS`^c(wv-n~>PiQ8H#Y6=E3J=!Qg=>Gu^$U(ojHLG(mZEB zEk&on!`TD;K`^7xH(nCwO`qF8(p@`PHE?>cVzAUu1fSdT`&uFmEwSc`a9y|;^1~1` zb1XH~?04%b3;5QZPigHNl0!$@4a03}8!c6qmBy+_A}lKrkKsLL>QcGCXJb+|fPIIT zfZYME;MR`*F_=UD7;K1>QYDsNfIP1l*yA9Hu=v4SJ0QM& zN_fwMNA}&`?e&0dUP>tXco+rMih(VBep7!6>K;@B@Lc;9p2;^S* zMm^wZ5oMhjvZ~yRJ5PfBVaL93T6U{@)v)xOTSWZzR*E?C0R6MV=Up%^oHztecknnP zM4BCt7(%-V@CsHeXXD!eE|kpBJ;&}CmE_`vvc@u13hVbE=BoGZyKZp*b#12R+@$4Gh|6Re*$~o?+|jKHruvB2WMa5FR@PN3t95PBs#r*UNK?i0p0Jm_ z7846&I+=g1D;n%<+0_%#&0UY`eOL6ThNec#%~(skDXsf-pUMtfh_nJmm&{ONcz@@{ z>-s^fAt3T@OtX@R3%Vpp2^?p#fQL*IDi>`gqG@wE2d^Z;Vux<;u;j{AjrZR?A?smP z6__ZzSN6+IJNsk0dGeY5vYuL52{%^YRgpu@+Q@}X6@%#p?|*tMuj-bC55fYXV{>y+sitqaXYbw%9lF|9SBp6QjzZKbAPn1w4pUpTh`dhTEmH0bz`U+ ze}JU*fW{wT!W>B)9xzp;M6(EFIpo60$C+UcNB0nX+`{`Ut7$tZL+jap%lO2ZfuOFo z4_AB{5ZYhfm6YW`Lm9nF{sym#Y{Vx;F)_Hev-Qw;ea-qq?akXaB);vj*qNf{c)X>k zs3jh6E&>#@Qda~VTi{KkSd=9!6c@HsPhKim3=6J0VEC;7SP^ze z+XBi_37oZTYUU1NGL=&au}vqtEyd&Y%b`P09ou*^9Z)@{PYxY;VqM3Omn(&MXXk(^ zn_iC=*Xkxtq)Rr8mu|XsW9|4A>C*8HC7W*F_?q>-Wg{ac=`qH}(j_A!WxeY`%?OrMh^vlGPR#lpfLV03!^y{#zGo{ODh&W zc5|cVXbev@5i8})T~`r{M}pden&v*|i5Tn|K2cj`40n#4YB8;2PwV|xq^C7Td1EnD z24Y%yDx>$R4ddsBA&iQFOA^iVY7DXi=F}Kv2k&U-8pHVhw8r=|x9(}$Gf-?;C$bu& zseC?-@f?DriJ^ntb7%~71{U6nX)UZV9=l9qd>skUfT+uvKljY9F^aI}H$tA2L7tG~ zZks%CueinliO$j(ISD*lBD2`$Yx)DKG0{>UQN3FqI68K`+o!4>soI3$-S_lFWe)^W zq`8v6hFeaQwO4sOfx7atwz$XRuhS9(JDbvbqtOk`J%_u?(-ZYgd`~_yX zogHHD5^){%%P9Vl5-(b^D%`I6%sxxeCm+X~uqHgAYGG~iR#n65kY*73F=7fB!CG7? z5hWAAk}TdQL^;k7Q4$B|{KoyxH`4gVIm{>}a(M7(oaWECUl_Nafl-F$e8wf`86)_{ z_52$gg8Uh$_%kjE8*=mLoAVhDXP<$2Tr=l09(JCw0pB>yzrk_9M>)<%c~}_bqjcjN z_Dnej_%|r#B8v|TC9ZeFC;HCRF4pV%5W>%tye0b@W-dh&NRIIc2fxFOeSRwvIWx9S z6*bv+#rVW9@>7cMR9jJrM^Z(>}t}Pwdv}vHUws>IEp>hOeBHpN3 z5sW0GM%08?^#4xncYO4j- zQXWA`D1K>|jG)_>5E_~K+|+(njin$GM!6=MH)Kb?XUs)3_ls=uEeIb$g+$q(EDnkT{%G_c!+zc&+E*;YN zjaa(o34a$aDpT~$jkT)WzU93Y^#M&qIisdv-;-geF-7&H4XqJ5%#`9qcaQd_s`fG< z`b&UL3X`iuu8AW$ZO?)toi@Ck0>VT>rWkJe62azKY>?8Jq`zD9$vZG~DuKJICz6mo zk&9ztAR=LCErQSZD{NfQ{>IRnBZC+05B>s9uJ<)Vdo(@oUMgRJJ?8YmzNtb z2kSaZRa64FyCs82EEp^k-M)~|ugdG;@U|hl{Aq%OC;X((C@)I1MHQ)e(|d#EaW5t) zAP^h%2V(f4_6CHk2_EgTTGC!s(USlyzKOXNV{Ro>&cRUyLdk-G5W+1@s-WQ11BdU5 z`q47gQ&gc{C;OEFMH86f*-+YDrYaptNN&r&ZDsdQ^Y!WOA$;8|Ok9GEk zB~Ltx^omq7*51|~kle9A(CbkT36!vdn-E1ic?;#Dq7M~ zUe;0)tOV}0sI&A2Li7NSf<}^`VdV;u5}-)cYQDiazHzc(520hcBl%g&Yw|G zQ5m4Tv9!BfQ98FYG!B=mp3(~CEHKaY;pj0pfVG6!WnsaRuNJu9gn zCU6tj|Np56UF)WP%{*)`X?{CB$2pbffMhAe(-NQ3f<|e-ySGda8I`7>_@i+sL={;B zHP-RK)|AE6B3SRS%5-T^jcPFd)=m8nDsNxHLqYkMKbBHV6q%$*Wp?*nME-yp&?;Mn z=2|`Ejae8bCPj)N6#JDTbyU+v)u=k63)+`8rdBqc?CUfIHKhBrNO>X>RU&HUr}*wV zHKro0w@!D0xw4)0ooMpofaLe6a$ zwOeugB&=3c^`*;3uHCxvWM2t0!xt+5f4>XM9N0mizDB+w411M0Ds_u?PWKxPYFLH@wJDfbxt>>AlN~? z(I{fMHpix&%$!WH1EZx<$kQcWRJ}~!ip@pkZnwIBKT@_8o`AenXI^y>kveUw5^z^Q zR~|T^dOYRWjIV}%Or5IR({o()de!4S9yc!iVlpKLlrF`- z59*Fion&7W6}KdQgz_s>AHwxHe*HXjJ5uXfjs*weQsQ1n`JgBAB3=TX2>XDc9fZa^7{ThlI#uENvg;Q} z34Dk{<2|_kGk*PHo_$)!Qfye5ga!N|*NxmJuEm`szw=?&J+K-XlG`rV-@D#NHYj;W zS=B(`3IKT}@Z#@z9|R+bhj3b-GmD){;`aMoHS)CrDzBAhhbpbURM7GI1w z1|JIX?=4>SZ@ppKq4_EFss6LPu|$^w9)FALoqSCQ3eJXO$E>ktUzZ^^5yMb7VaS*e z)bD_EPSJL{rq$np)fVMlgK>$`Z5F=l9oCNMKTC7J0^0#@!|1t68(;{MWd@cf@bsg2 z`ptmt5sdaHc*Vl?yPVg5L4M{h2=5uxDB|KS8quy5eQ|0ts}>{&m*6u>^biHmc&Iku zkaldZj&Ea?M`#>fXGih;ciPm2=Q+5nLoNRv8i@VHtbts+0pPpf$hW#i>;;j*>xM?R z)w?}tHY)5U3t*0g{*bh+C>X6h-6=`7;^Eq~U-FxGlEu-r_oj_o4mYcknr!cEMyaT% z_>2!=X21)?s*Q)Q>xyJ}61}bUXa`sBOV;RK%c$KtTvOdQT3X%L*3?uadu6Zp>v`f; zaNUl|u(t}bJ@--D+b}W52v1r%tYeA^9st0aV5nRUJi*IDIL_oHt1?`dMj?;anf!%~ zTaGlVvRc#8*8Z?oJFvX?CcwA!{G{lYS!#qoAYK*Sg@5tlk0ib#okZi zVNWi*2$Uu}<>t|-4oGJ37H{DNOQ+`PwmcU3|(wVen-C$7%D+X%5hwZw;-cRTOSR3S%ge~aE-e|7WK zDX)6M)OKjz`}yCKsHs#>*nhpaZQjrSo>UFGts4JxKUBcyr~X_xi>iO%m;_~h7@|to zWPu?@c+`|+>;((?_6Bva6<&(|@(Z#b=(>IC&)IwIA5&2V>KO=QcA?68zlr#p*SpJS zA#ZAU_xd%l#qjy`m%pOZZ$(z&`b)-j$evkJDGIIx=Cso&2Mdc3K^0z9jiSH`e=y|^ zmY(`I_V+a9^|OBYA^b9mUtVoLL1*w0uclvK&5NcQT|Z#&W4F*RNiq`NvWeq$V3iQu zE!Ky8EV8ir51i~O(ua_#&M(1U@8h-xu2CAa@RNS;@+V>4^vlmL{7Yf?T)#wl-3NtB z*lXmVDu4DK$ZJX+Ic<0a-5rZ|)LB+= zaCcYK4Hhw~TTRpVC{y*8NUZzV*pbt}0EL$hZw zdg$J_WCz)I$BylHt5G}U@wqzA#r zZ?2xWep6ka<*|xu%zz?Uy>*+eo2Z6!aYQwkn3(7v-e;+;>r;K3s@%*_j}V(frk!FR z#&nVC-h;dh-!B2W;iLm)>&WeN2Zhb3u!wAlRKj+6I^NZPxYuu~_FO#`W<^r<<)(@~ z8}9mnlwsOa^{S0^*{O;OOH7=bsPDBTv$&?%l+3=mP1ldt7@9NHzL9;F*0Qd)f4o|x zsj4K)z6&4b^O!1vB!tJTtp*Cmj=iiUtifvfD0uXjutjL2*Tp90=N?|lEU7v zo0GSgI^V80^*kQ>4*Q{Gb7T!OEViQ~w@Hh=3QyxtMZq0C>y{^Pf$#`I6^V+ezx*Vb z)+e!rL*d*FmXS2b@#o6Em4EK;d-27}n#iYdmVF2R2ZlojS^Bdl#I_Q=F zR^7OxAJZrvJ$%o_#rdFi>M0?H;dluJryH9O3S@)6{=k!><&(4*Y0DKE3xQt=7mi4Lri3GSn zJIopOCqUyjF;^ZcoR16KAd}}o{lCI1sMMj?Fatl#$pv2p06r{s&_fsCf_LC)AH_3% z2?C+iwar`fe6hpQUVf68E6W93m%eN2N#U4Ha+DOEU(U1p7Zvo2Q@Cq4hLh~!5bewo z+AKj&6n-_>*x{mDo5F1_f}rP&HhQQ43P;FzVb9)l=X>@6^)rrVkKeJ6@`wO=omqR> zv3RqkfLy9!5j;ka_axRpK?Afrx(!j8t%~MG(7<{0r*rRMjE}J|2=(v;dH5hdJVOu8 zkIm3E>&-n-6)8ZId8^m$&WUq1z17}NDek~yqs|g|0 zbzj=6cwjzTnIDL%`yC!PLm>@)F2aQkiT3Aie7;`vd``BMR>hJ(=MfF{3d^Tmd#&cP zu278yKEfhmSj5@9MR1lt_fFfKhxg%_S)}b9nn=&{F&pHwHuOt-Wr=33(xfFf)0wXR zTGBHAm(SY%oMx?xis$VTwh0QF_G^#6zTkP!SQ1bOOt5o&5#)$01nB=*J{&O)fW;2x z##snd^~+x>kaCKBjQu3XF^&$&nlH0MUUyguM6J)b5qkmFxh>xta@V?N9jrt4F`xcr z6UW|tS%DaKc5t6Rbjd;Z>ccgpPi~e z%HRhsYyojBP=r9>RpjjK4$A#yS%DIg(-9#N_0aoZe~{f#QdSd{c5cHJ?V8^zTf^xaOgaK~#HaZnJN5 zD&Ab;(W=son}o(WcY9e|ibO8Pha=0i|;uAeyk6v~Ds(p9uj(RMt`TB>3w{?V6 zY$ZU>f_cQMD<4SIwi&WqR+8+%OZfxM`)=7_Hg`6Ahi^XA(Xt;k1uczc`&d;Vsu^XW z^T)3^UmWt1t@(v`Rk*^8^j2&=)7E>{djHUH@a(NtkynCG=9b-+y$M#^nXYMxb)~6p zTtwXAm%=|oD0X1$aNhq*4f@0xWnTcRiS`BEiM4 zw_n>}s;!%v%KeHqdj0tN-EmEA-O_waYlupLGsthb%j#Rg2P6Tm_+!|`m}tGGvOHaU zZF#HY3D#ayR9EWul$92>NTOG3J37)Z))TECuWs4V-nyf?cBCtIo42Rg)RkaIZ)fBJ z>OeGEY>1cN7YIIVHk6hmLu`u?D-V>!E6e;8Tp61BLtcRiZr+1sQSd73)dqQI8}ep? zAd(4vZ6LAk5M?^pe+2WrK;ArHV zy}Q~%Zg_O(L205b+-CA{Zd0jBf-_@j^Dr@eD=(-|nej^_B7e|d?*XGWK^+mo^wEaM5 z+gLd^w#ceqrw=1W2p`su75S6V_WfP#upILTO0i|rls&~he@WEvg0yOW@b zdrCCJlmq@q+%K1u$iAwGKPZ`oR@|FJ+s}L`Y@{^6!f+rDI>?!g_>7y=S$0dvDE)xA z0$C&y?C7T3Y1Q`n9Y}2KJ%4P}!1|B$_28Y?2=^UsM08-x6S-8qA*CwKWff>0!YsX) zvZJkGPh_;Gs7MsO#XXC!`4l=!t&2pvn`%3ZYefl%h7Pnkukm=dtW;FRyU{O}U2NLg z+Pbx|k^VLvtFNl6r~jePzcJOyHj4K{U(N`~k+caxhI|*Y(KKKMu`5eT_WCw;`8W>FJplkl(J! zzk)zSn-lgTaD^hbo9W3m7J#svV$7KwH2Q-Oh}&+$5Y(6Mrb^fphq0K-o2U{TcP?zh z9gJ|Tr5)7GH_)hWpyo>!Hk(tG2%0RRe(-sUd(milnXd)Lowjp`WS+&~B{yME3Siz; z=DgD{Ah!(|AoqO}06}xHKchZTH=*u8v$T6GYKZh0wMDWn(9|yE-MEKCz7aa`ap4q- z!g5=>a)O8kkJ}bO7B;X3I=Ud5Nocd!{_E>4=8;(R#Ccju??HuA~yGytQ&#c z06Dnd2cS^_`Z^b~*c?%|!yctA*IXexYAi+Dq;oNhY;p#&Bv)_GH+5!h7_MwefmGT< zdDdsJ2etvMx7#(KG>q0RV&p@|<5hb@I)#YYP6d}`Z`ZGpg!+jpdo4oAI#t+#J3 zX^5*D43(nBN==h0pcS70kUg2#u(Jg0$=h_x^srNzcaWxx)2+B>T}a=!XW#km@}c9y zdu~kMS<=(g)LUHK+tl1s3`S_4`lPr=_|Yq9&fReIzAcV97us_E)iCGAgBqE0-oDMX z@um_qh3;wCG877(g*m5-fJi6EEzg`Y66dbkcei8Cor5{o9-cPm5~m)hu5E{E<>s8C zlnuA+yLscZId|Zev2bgHW6pU?v*sKD?C&e*HRlYJ=EPyn)#aIU%w@pR838Gy)`7?S zKmfLRnszRQFBKx9zdcA*;7L>2R4+5%&%X< z@`Z}>S_H{ZdRdO1M?TrqEP)7y5UmrKoc|yc^7bn zU?_1NiMJ9?wvrN6P%Bj^kDNj10{C=xh#@n#m zRNP-#*a@#MkQTFTM8eV6fCY2nSV~4{>0Z-7DQZK!Z-XS2tn1x$yvFOlbTwME=u{Wr z8{QA|&{7}PEKhSyW1s8}_jMgOQ{@f5>LPGU$QsxBb~hm) zeT;Co**ml~p?DQF60fKXl}8MJ@BX2qSF2+{o9M!BHN?L@i@4MfZJgm24!7j^Tq$D) zGnPBA+_lOs&lGD&9RR6Wi8cG0-3fy>8YmARdG(d+&uyzxu!hIHUcuAZ+_%eD8fxon z9*?Si@1sb^7(E9rX3l^}$<1YtIBzn~((>Vev4=s?)VfKl*?eyNb;s`+jt}l>R}I~& zuU^0NkzE_B8!X+cw(l8?f73#_1Go==ut|D5CBnDsCe|5-qIeb7*$-EVTeMl5l}s`+ z;W=a3Nh@Bhdzmw73bU6u`k^lBh1Kj8_(^Kx^gtf$Gk~y(bRO-UGW8SzBc+??r{98@ zzXz@UT_~syoIyLUUMD>Tlkt{hT(jZ{qP)^$&$=ED%WnrJ;c@rwwK~{}D zqX}8|wls}^;9wW&?A@3zz4?RDU2HI8~7(3 z`=vFjyfabRRcUExF=*;-niVnHhAIY*_e!44neXe8qO%W}dMlA6tUD}xr$!BJ#y-g4v!q<)T;@V*>bVu*Z4 zfeGySs?LUFZKN#WMaPnB6-bR8-J-~7-ziDNR>3U>4m^5j-%V{MJZ1C?5QIdsxknc~ zysa>O=V>^Gv8wWTxT?X2&5lP9voI%)DpojRmLR{X%Oi(^;rg(pgXr`k@1Bc;eb-K) z{@9BO{IoX)b9k$6h3li9K)@R>Mt>D$_&^izg&>;nobVB(73&;)W!IV`Izopyi_$)b z{Nmo{ocRk#M{^c=ZVzba1+-ltTEbnTCEDxE9%P(e!>ffB6kKpm2$T}Sh}PO~O|16FN;YubvEl{PR*D_Tl^j`{Q!ytbis ztrg`im^^Cxgnz;0DIPiO2%hQw=CBQHDgafWAtibi&jRG^>wf?Pwmd?u1hrc&Q`r3x zH??L!%UzLW{;n0X%=|ajM?qEgehzgsm_CbT&$wf0-(l~Nkaf4DU;Rq5yo%@%Ge^Ip zS?j0O#~Y@V3d*mYx;d0z{{=4yi@D;$Mj=fO88SNgE|RmJX?mwseF-y25jj|Z>~l%X zZWk_+&%pq*aPhtrCLXsmh>A_R^*(~|`z*XQKfwL5PS;O`J?tzwseCXDkwrTRUmt$V z{t0j)KKLm;0>8%}$eOULRoE%i@@aCTEN7YJY%*?`ku?TO?D!aJ@!xy~cGUqjB%gUJ zOs_G-4c>YcZtsVsb=6zcaQXmDrb`bfA!S^aA9`3(_QRTb=n}3s%JQWLWT3pt)x`cA zR-qGw&dxb20kXW3z4pvPIpyfdZ9IXsQD)xHUjyhw!re(d^FzGhM#B@%8+7nIMC@}2 zBzd!iDg)?0{P{m<>PWEI#*;$D*gILler)^e**Rt5IGfB`@nixgdxFdnOeXW5*>`S$ z!Awuzu35jCehZ-cTwx(1jFJ01i#D>NV-B}{CcUgj6uG+7A=|Ut{s^L*X7km0RAsLB z%2KM2W)SXC{Q5uD;j?g9>*sU1lmA_h4R;#aKVyn_^1thN9jD>?|C+lNAUTTj zywfu~@7c2yJJ$ED7TH$D&1kD!B=E9!V)~eDJtxK{psih+0V)3>h$tj5?)V zk|7)VUdNX2J}x`@COhnfM~uCkvn{ho<~Y@&4m^J_I>6K5WWKy zS?Mu=AZLU-WB>$PM;zX7e@`a}t`o8_sFY@`&RHqfOweAz=FA)iiKR_(cQd+P4-nFK5ga&1?n={Mc>^yIr4#Pr z1kN#@2pjiuv>Ye&9Oqx}HNsES;42%r2w{gsxa{I$W0EF`SP4(o8sD{ zRP^35Bwd)a!V{59%(Tq7!X&}6*0`k@E=NAB`VD+b zBI&_!&EWBzi56F#PL~kP;*ST$+YHrQuyb|i@*XF%cvbfxf3R@Z`K_aUk>;i2&B=~@ zlO|co=IFd7hF%c9Tv(zT#Z0neUXvzT$#h@qIqOpAONhj%S)8A+!{ zTCPcEv!B@JdhRuL| zGA}hR5j*{~rZ-wJF|HpN#X)d|=h0a`toA_Nl_5XZ%fA$Jk~Jng&Sdq8jji=r{yP2pVyJG?2R!`yWR((?TyhDv9vxZU!mH-#BETOc!Ks zQV0I#ewIfbk0WFfDtP4g~A70zs-7Jd|uE^5q zu0azrkSwS5C0DFjvwKKUJI0o!aCT}THJF*WYM~c`xzzC+1;~5rfy!eUQgw@^l8Yfo6@d|#D->+_%f@gTZK zN#&GXi9r!@7H;znRcPJFIm&^!=zcnQgYFkU1H4A@DHNuqwI>lakqeFpHV47c7b3yD z=K@~^Guk*eX%S9ju7ZJpAYEwbPd#WVV10GE(^_dU9T;bMcJ=>6T3jE3W!I3W_8@7| zMG2(ExV18*D8)rClJo-;e}r!iPSU?`M{vaPIY^5PcdWE6tFqD%rO&R}$b~BzZO3%Bc((`)qzE>XqCyer9@bAyCDM-aMN}mg%gRw>f z``(gslPWXdV5*{vXfl_Tn5j`o?c2!K6i16Nol`^ga7LytD5LH5>~-NO@z}?;J+*u+ zp?PhK!9-m??YFI=?bl~-`+9bX(8NAO_H4>v>1+N;?0BIj<2T!lOtV93L>*KFbuelJ ztQ*Vo1gHE6b}psu@v6G!jV~xsrC*l&m59=(3d(b++fR=a{EL!5(-#6y2$ry#>K>j^ z_vgVVGV98{2;0<)y5B)ve3$za$+vROL2nT(EoN>KO&s=Du97N=3rDxhq@J8?pEN{Z7bcR7v~rk zk04@QBZbFu7Ya~L%LHI~Q;$+L{(14|=pUY=y_VHuhi{;{z!I?S>Y1>u0U7si{|2yn zEqb%p4nIz_5|syRdw?$+nw3~^z{0D1`3$lx!gjGp8Yt{GN`DJVLLCnDBNhw^gh*L~ zM~Jl!PMQ`-E=v($R;gy8L9YvSh7(#Y=A?_p0_(#5HXL$hqn%Z4B^qa2Oe3C6Gl0Yz z!&WAv4ln8|_H;^+hu};{LDav__6J@S=LHPv9i5{(HU8~Ts4*O3`$PAKLl02Gim#Vm z4ZK?Z-PzwOy;^ziQ*4jWFOI{^X0BOe55V!BGRqJ3gzHt)FdIUYSw0KO0Ur((NzY*b z<|jSZvu@J!XjGL&Max*EDcMzePiQMYQ`2Rf$EYVnQh1yqq0!3~fueFqQx&blC1M|<>nEq>?7lm;sGmU{KJ zl=ce)%uEs_qoBJ%xsj3(i^LgS{!})WM${p=c3hxQ-wmS!M6_0VdGOMFN;W+jJUe z&q+=LhYWx5?mDp5%aGlM5G&K(cE^!`U_W~S5`Cd4eHEe_Ltw=1MJEO>Qk3?sRL|7gent@>-M8 z&hAPpuT@$BQw7*q;4&QJ1+fK@j-Xwl_2_2CpDaM^V?*&4m=6lOnf(W)o}EcyX&Oi@z~Z9SGEH44G_#md6X6AF zRMC}0LN{9TdPAt&uw^GkbhSR0N2oyou05fI8EPox7)&vc<_5Wl%8v*i1+r{2#cEo? zMGsH%$PK}oRSzb5-4Ed-Kf_vpl`k#5UY;sHj5@Gbb#-5UEv~e7Z#l?9xc6wOcW1G1!;7GsMUD+^A!E5bfWZnV1@hqB6_~cd;Tz< zkGan`(~i90W{{ook@98_z8TQf!c&0&Lt0ec92lB?NCP!!IYEPv5+gLSV0?W|snVc7 zB82!`gc11-sO>A4>S@sUf zzroARxS}txDU`3`#FG^!pIKdJv-w z#xSsT5LYWvhlwHWW-or-=XK&an$X3)yveI8UEIUVhk3bytrgbt@-@6%$JPc;B7TD` zUCYbO`29FLiSl(`{q4d*_7jw^ClC?uYf|_CnU(?KDCPjFRZok}K@|B1J{1mk4CF-6ASgoU8V?q~xjG16{b?ww)H--|=^FpFA6lGsfiz?<`Ss`gWh5Fl2pD*+23q-}u1lVaaCLajd<{dElQt#IhL~05tD)yNQ zFfCuMkX%g=yu~4au?<~9`pZzEtpYPS9&DChUh`ISr)-3=V&h80zA`Eb%5`?M^ri*o zl|P9|>a})^O(86sxKGy{Ro)-2{_Y}6_zF5a`<-V8a{MSan~sJEJ<2*D!Rmo``@|)h zrJ;2+Ysj*(AAWqI)Ym5w2T22|v|EizchdQA)_~mQoI-JanfBkTzJL4t@gXwTj)}?WraewrY=u~+RWY*?iFt&4H%X?$#U-95|0~0B8s~(!=eyQ!tffh-PzU{iP)B**d1++=;T>8#g>YfRF3dw!5>sjfn5C;$Q715ZtyDG(Os?GnkEsox&n(;ngH2*D-0?Z zH?R&t@le|%Rdg+U*p2#3M2_ZUWZ2WV@gZXyVG)08M2Tbls_IZ@V|OGJ*Ud=ON{FIm znTbd+B1vj*ZL5wAhvmc% z-Lp_932Wzexcj-(X%f^)h8SR8CaW%W;)k?bze1h7o!Dt3xzZINPG5Ae)qf8WJ=mnJ z2KSl@66g4|i682y585<32ikuPUrbnOeSZePJ*s<_~dC3B9>E^_0H*2 z(x*?`L;4u)7yLohDhk85{A_e(ph9}CIul(PtB{_TW+5#e(Lr~gl)_A|MgmV_x#mP+ zgz{Z%N8p&)NZf%dm$>BLV}f^TvV5M}045k|&P4IEYMsM&)UbzG1ohjl`7We8e^#$@s$@aFm z9w~6i*?33kAHcK1YDgEhov=>)9qvrYE9Fc+D194-7LIi%X8NEAPry6_h`d&n^H Qj0WEK!@7-Tfc%608!bzM(*OVf literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-BoldItalic.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-BoldItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..bbcffcada2fa38289623aeb257f97d4036810d30 GIT binary patch literal 63004 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�l)SPgy0t$l+L3H6QU2gdVGlC0;d&kE^B-tFFz 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 z zdw|&O$4C7}5*duT?8%M=q{pk6KE{*N*^uW$`ScOQSQZZLeY5Y(jO*;YC&gevQ7oh$ zsBiR3&FweMxEP>}N3Np17-(-S4F&-KkOKiSElzt=nHJ|Vmql;!Z0?WRa+;apaxyok z)omvT1VX}q4W0hBYy^m`qo@OjE-`ZuHYCfEGp!I2VGY@dfIukr!CIII6vv3zrs$eU z#WqHr$kAAbEtpB1pkmu>Luk`T(m9E^VFW4DB|y3CQ}XpqgYEW;c3Eg}@yHoI$Z6CJ3WAgT;nXoWTZRltJaIHA1=OFDeOrlZU^}#Af=! zpGfE`DbL2GO*l$GLi-(WHz?Sxcl-&6t}*=NV^tE#13-qhX>%}QQ!I7O1Yur8 zkxYsy?U*5Ze^|?Dfo0QFmSdJVFk8|P0Lq>+?ifH2Db(kN_O<0u0**T7NV7$R5dcsW z2Es9s4h@vJL(3e*x+Oqx9c6&vI>tN&0_+PS5C}asiIZaqfwYM?sP*qGw!Cg-7njCrsrOk5)(oit2A)JaPmCv6M@2u+oBvCW}< zK_WBqsM{uy$p8@trn*iUmR#G4LO}_Vm|C~`RLhkRD3h)Mc)~Pae6qCIeZ}P2C;@md z+}|d*XKUei=7ZsXXZQZ*&Nlb@-B_&lA(MHPzb$v6mQ$-aw^^=M%hC9-)IG(bck-(5 z&TMzsx^t>!*8cdULXt$uO2*(c`O1B~emC|n)AMhg#kCW$nIGQS7Sr7d`VM~(?9^2) z@%eb^jqk>Z-JNS^S>(RQiY&FHFK5oHP--nSzPJp|dzUP;y!m(jXQDuY$=F=Pneb71 z{Au|v{E3;vhDF#C$XC?q&yW8mrHs|8xIq}$3Uf*57x(G&yTQU%EqBLFs1yZ!#XLT~ z>b_5}+Af$a@_7qRUyN#;&lg+L$;x)Z%{kb_^&sO^U)xG<)zT!JSX!^oSQ)I(jT={J z?bOsxcL)(SII_w6+RJO1lyg?DoBd*4YpnjoR$|jFhZ=IMp+k4+^wsIz(Kq39*1YD{ zdB-je6AvcG+dKWXMH}fO=y*T(HQ!YH96Nr!8Wzh+z?}XFIlkymis==f?vQU$!E3h z&-YJ7KDa8iQzl;`TpBLz=fIZ-Do4knBTaOs0X_;V8m*&ndnAvRD(Z?_)}A7{$$U8 z4P-x+EWdC{wDGT4k#N2qXG3}z@xwmZc-zZ#0BuQW=d06jU$z6!o46ebrVIPR%>vev z56=esOG_md)G1Nx5C8c-cH!AG=?{NR=HexbmFZR{xu8NBT>xT*c`X*8Q+6<~M&N1X zy-%QBc7@}I5NWPDol1x$BV}?T?_-3D1UBOuy&B~9-sY3xELv_hW8rl@y&QuoK2NI> zA;M2{?R|N%XQw9@(!oMvn3(3h$**UXgYdgjcd?wjzjsM)E1UjDpz7t-Z$h}8?#Uw6 ztnnXRcK%syPua!OY0%v@Qw=BCN4U@SF?XsNz4U>@`d!y_`WaBa;?u`cQX?ekbzV-F z%H9@du?yvtGA%&$#q@@!m@HbhQ*e0Go4xM^UT3Gyi{dJFVc$!k?lq*(4sN0Wfe?(K z7)~%qN~W8X`%Mfn^Q%7`dY_qu?)_Tx=XIT4oG)H|-KUMf#G1T1BRhsu5r*1{47h}2 z#Z%m9UGQMt$$cx{&Pvsd?UXyMb_Qr*4p^RB@#c5(bFrxE$N|qI+&o4#b5A8#pw&x; ipYlih`_-1s_Xa+CZdsoB<){DNEi+#GzrE%U0000{kT{V5 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBold.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3b1e1903613de0b31200199367ca3f6efe139629 GIT binary patch literal 208216 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%0Anrl@gTx0 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

    9~&uIB;&4@anm2o0Ov6b`owfQ^Z_Ux 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

  1. {T$9oST4(AhCarM)%u+^ESAUe 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

    rd^dg)lU916x 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

    rbqXHHSp}SH8n9L>lGv;Lashy96FBbFalI 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 F{sXblZiD~; literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBold.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..877fb4d05d3f25e90da5f11fdb8417f6240af358 GIT binary patch literal 61304 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 Be60Wg literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBoldItalic.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..59cd758652c591a09b9565259393f4c8571497ad GIT binary patch literal 207340 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 Ute)@a>3uGwA0X>5J|IE-7l$~vmjD0& literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBoldItalic.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-ExtraBoldItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..8ddb17f011223b2323e543b8ef70b5fe2a2d6e46 GIT binary patch literal 62660 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 b1+(rHY;gBzX^6Xu#1#2x!gtukK0)v|GCySp literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Italic.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..b946bfec36015ac9137d174deef114e3dc08937c GIT binary patch literal 62132 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 XfbNtQUSqpltV9IN;q*sEM85xj112Le literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Light.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Light.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..03520b723f65b4dcb72abaee063ecd9e2562bc98 GIT binary patch literal 55640 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ⅈh4(HiG(x$L9^iJujf+uU)Y>vt16% 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 U(yJ|b$PXg_Py6N`|B;wK0vV4ZBme*a literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-LightItalic.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-LightItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b028d93c857518a0c09c25dd42b6cd60edc0efb1 GIT binary patch literal 205676 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%0DFOxP-?k_SY#+6D86({^+ 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%0D2Vw#EVaU_J;Rg9y4G_OrB3N*6(?vB9a)4 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 P@-`iZw%)N!^K<=Q5Vmm$ literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-LightItalic.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-LightItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..385470225ea459ade21ec550ab01ff7f788da88b GIT binary patch literal 57044 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 K_78_ICq3isXTM076`Fcfi^3jRkFQ*dqXskyPcR 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 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Medium.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Medium.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..5a274c4371976b2d14f5d02862f10854eb74dc2d GIT binary patch literal 61700 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 Wwj4Y0p-;b`FB7)^KRq1-0001z!FJ&Q literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-MediumItalic.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-MediumItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1a7d7f9f675620b421c326339426c126ac3efd3d GIT binary patch literal 207052 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 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-MediumItalic.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-MediumItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..69e661b02659b020f4b9e8e4ad7b41804edfc5ea GIT binary patch literal 63064 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 Q+S7U!`%OL({X~E8zqP+`hyVZp literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Regular.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..0c3320c12cbfbc4039e143e48d7f47d279263d7d GIT binary patch literal 61192 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�^B$;sP=|yUiAkvWd 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

    9K$)Qnbh+jwU5$WXXzxW%FQ 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 Pp62SuX{-KdN!I@bsx>D| literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBold.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..bb0c5806283d4306046dfecd25af3c1018de8696 GIT binary patch literal 61500 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 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBoldItalic.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..88729833c304c3ef092e978aafa56ed794f284c2 GIT binary patch literal 207188 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

    dIW*8foVQgTAv4I)JGG-Xdm|-kq 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

    +_Q^GL>o>O0`U-SE^DfRVmd? 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 J4x{T+@IU>1JZAs^ literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBoldItalic.woff2 b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-SemiBoldItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..1b2bd0ed5df7525076eda60ad1a1fb526e0f998e GIT binary patch literal 63016 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

    motN8bbX}`O|2m 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

    #W%r5rGO5dRifBq_d8sp4?( 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 = ({ url, theme }) => { + // For v9 theme + const rubik: FontFace = { + family: 'Rubik', + variants: [ + { + weight: 300, + style: 'normal', + sources: [`${url}/fonts/rubik/static/Rubik-Light.woff2`], + }, + { + weight: 300, + style: 'italic', + sources: [`${url}/fonts/rubik/static/Rubik-LightItalic.woff2`], + }, + { + weight: 400, + style: 'normal', + sources: [`${url}/fonts/rubik/static/Rubik-Regular.woff2`], + }, + { + weight: 400, + style: 'italic', + sources: [`${url}/fonts/rubik/static/Rubik-Italic.woff2`], + }, + { + weight: 500, + style: 'normal', + sources: [`${url}/fonts/rubik/static/Rubik-Medium.woff2`], + }, + { + weight: 500, + style: 'italic', + sources: [`${url}/fonts/rubik/static/Rubik-MediumItalic.woff2`], + }, + { + weight: 600, + style: 'normal', + sources: [`${url}/fonts/rubik/static/Rubik-SemiBold.woff2`], + }, + { + weight: 600, + style: 'italic', + sources: [`${url}/fonts/rubik/static/Rubik-SemiBoldItalic.woff2`], + }, + { + weight: 700, + style: 'normal', + sources: [`${url}/fonts/rubik/static/Rubik-Bold.woff2`], + }, + { + weight: 700, + style: 'italic', + sources: [`${url}/fonts/rubik/static/Rubik-BoldItalic.woff2`], + }, + { + weight: 800, + style: 'normal', + sources: [`${url}/fonts/rubik/static/Rubik-ExtraBold.woff2`], + }, + { + weight: 800, + style: 'italic', + sources: [`${url}/fonts/rubik/static/Rubik-ExtraBoldItalic.woff2`], + }, + { + weight: 900, + style: 'normal', + sources: [`${url}/fonts/rubik/static/Rubik-Black.woff2`], + }, + { + weight: 900, + style: 'italic', + sources: [`${url}/fonts/rubik/static/Rubik-BlackItalic.woff2`], + }, + ], + }; + const firaCode: FontFace = { + family: 'Fira Code', + variants: [ + { + weight: 300, + style: 'normal', + sources: [`${url}/fonts/fira_code/static/FiraCode-Light.woff2`], + }, + { + weight: 400, + style: 'normal', + sources: [`${url}/fonts/fira_code/static/FiraCode-Regular.woff2`], + }, + { + weight: 500, + style: 'normal', + sources: [`${url}/fonts/fira_code/static/FiraCode-Medium.woff2`], + }, + { + weight: 600, + style: 'normal', + sources: [`${url}/fonts/fira_code/static/FiraCode-SemiBold.woff2`], + }, + { + weight: 700, + style: 'normal', + sources: [`${url}/fonts/fira_code/static/FiraCode-Bold.woff2`], + }, + ], + }; + // For next theme const sourceSans3: FontFace = { family: 'Source Sans 3', @@ -532,9 +639,22 @@ export const Fonts: FunctionComponent = ({ url, theme }) => { url('${url}/fonts/inter_ui/Inter-UI-italic.var.woff2') format('woff2'); } */ - const fontText = theme === 'v7' ? interUi : sourceSans3; - const fontCode = theme === 'v7' ? roboto : sourceCodePro; - const fontsDefinitionRules = [fontText, fontCode] + + const fontText = + ({ + v7: interUi, + v8: sourceSans3, + v9: rubik, + } as Record)[theme as string] || sourceSans3; + + const fontCode = + ({ + v7: roboto, + v8: sourceCodePro, + v9: firaCode, + } as Record)[theme as string] || sourceCodePro; + + const fontsDefinitionRules = [interUi, sourceSans3, roboto, sourceCodePro, rubik, firaCode] .flatMap(({ family, variants }) => variants.map(({ style, weight, format, sources, unicodeRange }) => { const src = sources diff --git a/src/core/server/rendering/views/theme.ts b/src/core/server/rendering/views/theme.ts index 736bbeca135d..ee628a856fb5 100644 --- a/src/core/server/rendering/views/theme.ts +++ b/src/core/server/rendering/views/theme.ts @@ -18,6 +18,10 @@ export const THEME_SOURCES: { [ThemeColorSchemes.LIGHT]: '@elastic/eui/dist/eui_theme_light.json', [ThemeColorSchemes.DARK]: '@elastic/eui/dist/eui_theme_dark.json', }, + v9: { + [ThemeColorSchemes.LIGHT]: '@elastic/eui/dist/eui_theme_v9_light.json', + [ThemeColorSchemes.DARK]: '@elastic/eui/dist/eui_theme_v9_dark.json', + }, default: { [ThemeColorSchemes.LIGHT]: '@elastic/eui/dist/eui_theme_next_light.json', [ThemeColorSchemes.DARK]: '@elastic/eui/dist/eui_theme_next_dark.json', diff --git a/src/core/server/ui_settings/settings/theme.test.ts b/src/core/server/ui_settings/settings/theme.test.ts index 0f0d8915833e..05c07372d1a7 100644 --- a/src/core/server/ui_settings/settings/theme.test.ts +++ b/src/core/server/ui_settings/settings/theme.test.ts @@ -59,10 +59,12 @@ describe('theme settings', () => { expect(() => validate('v7')).not.toThrow(); expect(() => validate('Next (preview)')).not.toThrow(); expect(() => validate('v12')).toThrowErrorMatchingInlineSnapshot(` -"types that failed validation: -- [0]: expected value to equal [v7] -- [1]: expected value to equal [Next (preview)]" -`); + "types that failed validation: + - [0]: expected value to equal [v7] + - [1]: expected value to equal [v8] + - [2]: expected value to equal [v9] + - [3]: expected value to equal [Next (preview)]" + `); }); }); }); diff --git a/src/core/server/ui_settings/settings/theme.ts b/src/core/server/ui_settings/settings/theme.ts index e157da9c514e..b2d0087108f0 100644 --- a/src/core/server/ui_settings/settings/theme.ts +++ b/src/core/server/ui_settings/settings/theme.ts @@ -35,6 +35,12 @@ import type { Type } from '@osd/config-schema'; import { UiSettingsParams } from '../../../types'; import { DEFAULT_THEME_VERSION } from '../ui_settings_config'; +// Setup theme options to be backwards compatible with the fact that v8 was persisted with its +// label rather than with the correct themeVersion value +const THEME_VERSIONS = Object.keys(themeVersionLabelMap); +const THEME_SCHEMA_VALUES = THEME_VERSIONS.concat(themeVersionLabelMap.v8); +const THEME_OPTIONS = THEME_VERSIONS.map((v) => (v !== 'v8' ? v : themeVersionLabelMap.v8)); + export const getThemeSettings = (): Record => { return { 'theme:darkMode': { @@ -53,9 +59,13 @@ export const getThemeSettings = (): Record => { name: i18n.translate('core.ui_settings.params.themeVersionTitle', { defaultMessage: 'Theme version', }), - value: themeVersionLabelMap[DEFAULT_THEME_VERSION], + value: + DEFAULT_THEME_VERSION === 'v8' + ? themeVersionLabelMap[DEFAULT_THEME_VERSION] + : DEFAULT_THEME_VERSION, type: 'select', - options: Object.values(themeVersionLabelMap), + options: THEME_OPTIONS, + optionLabels: themeVersionLabelMap, description: i18n.translate('core.ui_settings.params.themeVersionText', { defaultMessage: `

    Switch between the themes used for the current and next versions of OpenSearch Dashboards. A page refresh is required for the setting to be applied.

    `, values: { @@ -65,11 +75,7 @@ export const getThemeSettings = (): Record => { }), requiresPageReload: true, category: ['appearance'], - schema: schema.oneOf( - Object.keys(themeVersionLabelMap).map((v) => schema.literal(themeVersionLabelMap[v])) as [ - Type - ] - ), + schema: schema.oneOf(THEME_SCHEMA_VALUES.map((v) => schema.literal(v)) as [Type]), }, }; }; diff --git a/test/functional/screenshots/baseline/area_chart.png b/test/functional/screenshots/baseline/area_chart.png index 8975ae86c1adeef27d30df42de7c0efcd90ec3f8..239c8fff1843cbb01237a85f9113df5b9ec3ad3d 100644 GIT binary patch literal 52095 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 cL3uCO=VY>FaQf@D0r_aIv55FdsFaQ7m diff --git a/test/functional/screenshots/baseline/tsvb_dashboard.png b/test/functional/screenshots/baseline/tsvb_dashboard.png index 9b03e260d52c57cb7e39084ed63d4eb5bacd4891..b050f5bd1bf4d04b9bdf1178d5d8188911bf1316 100644 GIT binary patch literal 47315 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 From 06da6ce520f51299115aebefebcc914593873db8 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:44:07 -0700 Subject: [PATCH 215/276] [Vis-Builder] Fix Droppable Areas not highlighting while dragging a Field (#7527) (#7780) * [Vis-Builder] Highlight Droppable Areas while dragging a Field * Changeset file for PR #7527 created/updated --------- (cherry picked from commit 901ac51171498c3cc8daec1a9305856fa34ed680) Signed-off-by: Suchit Sahoo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7527.yml | 2 + .../components/data_tab/config_panel.tsx | 5 +- .../components/data_tab/constants.ts | 1 + .../components/data_tab/dropbox.tsx | 119 ++++++++++-------- .../application/components/data_tab/index.tsx | 52 +++++++- .../components/data_tab/schema_to_dropbox.tsx | 4 +- .../components/data_tab/use/use_dropbox.tsx | 3 + 7 files changed, 130 insertions(+), 56 deletions(-) create mode 100644 changelogs/fragments/7527.yml diff --git a/changelogs/fragments/7527.yml b/changelogs/fragments/7527.yml new file mode 100644 index 000000000000..b3bebe022ac2 --- /dev/null +++ b/changelogs/fragments/7527.yml @@ -0,0 +1,2 @@ +fix: +- Not highlighting Droppable Areas while dragging a field ([#7527](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7527)) \ No newline at end of file diff --git a/src/plugins/vis_builder/public/application/components/data_tab/config_panel.tsx b/src/plugins/vis_builder/public/application/components/data_tab/config_panel.tsx index ae9067cd676e..295a4a78f4c9 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/config_panel.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/config_panel.tsx @@ -31,6 +31,7 @@ export interface ConfigPanelProps { aggProps: AggProps; activeSchemaFields: SchemaDisplayStates; setActiveSchemaFields: React.Dispatch>; + isDragging: boolean; } export function ConfigPanel({ @@ -39,6 +40,7 @@ export function ConfigPanel({ aggProps, activeSchemaFields, setActiveSchemaFields, + isDragging, }: ConfigPanelProps) { if (!schemas) return null; @@ -46,7 +48,8 @@ export function ConfigPanel({ schemas, aggProps, activeSchemaFields, - setActiveSchemaFields + setActiveSchemaFields, + isDragging ); return ( diff --git a/src/plugins/vis_builder/public/application/components/data_tab/constants.ts b/src/plugins/vis_builder/public/application/components/data_tab/constants.ts index 9369bd78e143..aae4849074ea 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/constants.ts +++ b/src/plugins/vis_builder/public/application/components/data_tab/constants.ts @@ -9,3 +9,4 @@ export enum FIELD_SELECTOR_ID { NUMERICAL = 'numericalFields', META = 'metaFields', } +export const ADD_PANEL_PREFIX = 'AddPanel_'; 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 260b6e1261b8..6387e64e7349 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 @@ -53,6 +53,7 @@ const DropboxComponent = ({ isValidDropTarget, canDrop, dropProps, + isDragging, }: DropboxProps) => { const prefersReducedMotion = usePrefersReducedMotion(); const [closing, setClosing] = useState(false); @@ -79,58 +80,74 @@ const DropboxComponent = ({ droppableId={dropboxId} isCombineEnabled={true} > - {fields.map(({ id, label }, index) => ( - - - onEditField(id)}> - - {label} - - - animateDelete(id)} - data-test-subj="dropBoxRemoveBtn" - /> - - - ))} + {(provided, snapshot) => ( +
    + {fields.map(({ id, label }, index) => ( + + + onEditField(id)} + > + + {label} + + + animateDelete(id)} + data-test-subj="dropBoxRemoveBtn" + /> + + + ))} +
    + )} + + + {(provided, snapshot) => ( +
    + {fields.length < limit && ( + + + {i18n.translate('visBuilder.dropbox.addField.title', { + defaultMessage: 'Click or drop to add', + })} + + onAddField()} + data-test-subj="dropBoxAddBtn" + /> + + )} +
    + )}
    - {fields.length < limit && ( - - - {i18n.translate('visBuilder.dropbox.addField.title', { - defaultMessage: 'Click or drop to add', - })} - - onAddField()} - data-test-subj="dropBoxAddBtn" - /> - - )} ); diff --git a/src/plugins/vis_builder/public/application/components/data_tab/index.tsx b/src/plugins/vis_builder/public/application/components/data_tab/index.tsx index 8c79f680cb02..51a69950c719 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/index.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/index.tsx @@ -4,7 +4,7 @@ */ import React, { useEffect, useState } from 'react'; -import { DropResult, EuiDragDropContext } from '@elastic/eui'; +import { DraggableLocation, DropResult, EuiDragDropContext } from '@elastic/eui'; import { FieldSelector } from './field_selector'; import './index.scss'; @@ -15,7 +15,7 @@ import { useTypedDispatch, useTypedSelector } from '../../utils/state_management import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; import { VisBuilderServices } from '../../../types'; import { DropboxDisplay } from './dropbox'; -import { FIELD_SELECTOR_ID } from './constants'; +import { ADD_PANEL_PREFIX, FIELD_SELECTOR_ID } from './constants'; import { addFieldToConfiguration } from './drag_drop/add_field_to_configuration'; import { replaceFieldInConfiguration } from './drag_drop/replace_field_in_configuration'; import { reorderFieldsWithinSchema } from './drag_drop/reorder_fields_within_schema'; @@ -49,6 +49,7 @@ export const DataTab = () => { return acc; }, {}); }); + const [isDragging, setIsDragging] = useState(false); const dispatch = useTypedDispatch(); useEffect(() => { @@ -64,6 +65,7 @@ export const DataTab = () => { const handleDragEnd = (dropResult: DropResult) => { try { + setIsDragging(false); // Reseting the Dragging flag const { source, destination, combine } = dropResult; const destinationSchemaName = destination?.droppableId || combine?.droppableId; @@ -76,6 +78,49 @@ export const DataTab = () => { const panelGroups = Array.from(schemas.all.map((schema) => schema.name)); + if (destinationSchemaName.startsWith(ADD_PANEL_PREFIX)) { + const updatedDestinationSchemaName = destinationSchemaName.split(ADD_PANEL_PREFIX)[1]; + + if (Object.values(FIELD_SELECTOR_ID).includes(sourceSchemaName as FIELD_SELECTOR_ID)) { + if (panelGroups.includes(updatedDestinationSchemaName)) { + const newDropResult = { + ...dropResult, + destination: { + droppableId: updatedDestinationSchemaName, + index: 0, + } as DraggableLocation, + }; + addFieldToConfiguration({ + dropResult: newDropResult, + aggProps, + aggService, + activeSchemaFields, + dispatch, + schemas, + }); + } + } else if (panelGroups.includes(sourceSchemaName)) { + if (panelGroups.includes(updatedDestinationSchemaName)) { + const newDropResult = { + ...dropResult, + destination: { + droppableId: updatedDestinationSchemaName, + index: 0, + } as DraggableLocation, + }; + moveFieldBetweenSchemas({ + dropResult: newDropResult, + aggProps, + aggService, + activeSchemaFields, + dispatch, + schemas, + }); + } + } + return; + } + if (Object.values(FIELD_SELECTOR_ID).includes(sourceSchemaName as FIELD_SELECTOR_ID)) { if (panelGroups.includes(destinationSchemaName) && !combine) { addFieldToConfiguration({ @@ -134,7 +179,7 @@ export const DataTab = () => { }; return ( - + setIsDragging(true)}>
    { aggProps={aggProps} activeSchemaFields={activeSchemaFields} setActiveSchemaFields={setActiveSchemaFields} + isDragging={isDragging} />
    diff --git a/src/plugins/vis_builder/public/application/components/data_tab/schema_to_dropbox.tsx b/src/plugins/vis_builder/public/application/components/data_tab/schema_to_dropbox.tsx index 390e7fb47638..9e4a26b3adde 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/schema_to_dropbox.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/schema_to_dropbox.tsx @@ -13,7 +13,8 @@ export const mapSchemaToAggPanel = ( schemas: Schemas, aggProps: AggProps, activeSchemaFields: SchemaDisplayStates, - setActiveSchemaFields: React.Dispatch> + setActiveSchemaFields: React.Dispatch>, + isDragging: boolean ) => { const panelComponents = schemas.all.map((schema) => { return ( @@ -25,6 +26,7 @@ export const mapSchemaToAggPanel = ( aggProps={aggProps} activeSchemaFields={activeSchemaFields} setActiveSchemaFields={setActiveSchemaFields} + isDragging={isDragging} /> ); }); diff --git a/src/plugins/vis_builder/public/application/components/data_tab/use/use_dropbox.tsx b/src/plugins/vis_builder/public/application/components/data_tab/use/use_dropbox.tsx index d2d1be215785..25ea7c81f2f7 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/use/use_dropbox.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/use/use_dropbox.tsx @@ -26,6 +26,7 @@ export interface UseDropboxProps extends Pick { aggProps: AggProps; activeSchemaFields: SchemaDisplayStates; setActiveSchemaFields: React.Dispatch>; + isDragging: boolean; } export const useDropbox = (props: UseDropboxProps): DropboxProps => { @@ -36,6 +37,7 @@ export const useDropbox = (props: UseDropboxProps): DropboxProps => { aggProps, activeSchemaFields, setActiveSchemaFields, + isDragging, } = props; const [validAggTypes, setValidAggTypes] = useState([]); const { aggConfigs, indexPattern, aggs, timeRange } = aggProps; @@ -209,5 +211,6 @@ export const useDropbox = (props: UseDropboxProps): DropboxProps => { dragData, isValidDropTarget: canDrop, dropProps, + isDragging, }; }; From f4a80677aba8d95fd33922253f6b3e3c79db2838 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:54:41 +0800 Subject: [PATCH 216/276] feat: card section and dashboards section UX improvements (#7693) (#7779) (cherry picked from commit a258bd673d318f7aa8b2df3f47b0ca6b6a1fb554) Signed-off-by: Yulong Ruan Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../components/card_container/card_list.tsx | 26 +++- .../public/components/card_container/types.ts | 5 +- .../public/components/section_input.test.ts | 118 +++++++++++++++++- .../public/components/section_input.ts | 46 +++++-- .../services/content_management/types.ts | 9 +- 5 files changed, 185 insertions(+), 19 deletions(-) diff --git a/src/plugins/content_management/public/components/card_container/card_list.tsx b/src/plugins/content_management/public/components/card_container/card_list.tsx index 871c6451a8cb..37cf18adb048 100644 --- a/src/plugins/content_management/public/components/card_container/card_list.tsx +++ b/src/plugins/content_management/public/components/card_container/card_list.tsx @@ -22,6 +22,27 @@ interface Props { } const CardListInner = ({ embeddable, input, embeddableServices }: Props) => { + if (input.columns) { + const width = `${(1 / input.columns) * 100}%`; + const cards = Object.values(input.panels).map((panel) => { + const child = embeddable.getChild(panel.explicitInput.id); + return ( + + + + ); + }); + return ( + + {cards} + + ); + } + const cards = Object.values(input.panels).map((panel) => { const child = embeddable.getChild(panel.explicitInput.id); return ( @@ -31,10 +52,9 @@ const CardListInner = ({ embeddable, input, embeddableServices }: Props) => { ); }); - // TODO: we should perhaps display the cards in multiple rows when the actual number of cards exceed the column size return ( - - {input.columns ? cards.slice(0, input.columns) : cards} + + {cards} ); }; diff --git a/src/plugins/content_management/public/components/card_container/types.ts b/src/plugins/content_management/public/components/card_container/types.ts index 5c6ad129af66..8f4ea7855cab 100644 --- a/src/plugins/content_management/public/components/card_container/types.ts +++ b/src/plugins/content_management/public/components/card_container/types.ts @@ -13,7 +13,10 @@ export interface CardExplicitInput { getFooter?: () => React.ReactElement; } -export type CardContainerInput = ContainerInput & { columns?: number }; +export type CardContainerInput = ContainerInput & { + columns?: number; + wrap?: boolean; +}; /** * The props which allow to be updated after card container was created diff --git a/src/plugins/content_management/public/components/section_input.test.ts b/src/plugins/content_management/public/components/section_input.test.ts index be471c8428a2..80fe5ce0863c 100644 --- a/src/plugins/content_management/public/components/section_input.test.ts +++ b/src/plugins/content_management/public/components/section_input.test.ts @@ -5,7 +5,7 @@ import { coreMock } from '../../../../core/public/mocks'; import { Content, Section } from '../services'; -import { createCardInput, createDashboardInput } from './section_input'; +import { DASHBOARD_PANEL_WIDTH, createCardInput, createDashboardInput } from './section_input'; test('it should create card section input', () => { const section: Section = { id: 'section1', kind: 'card', order: 10 }; @@ -363,3 +363,119 @@ test('it should create section with a dynamic dashboard as content', async () => }, }); }); + +test('it renders content with custom width and height', async () => { + const customWidth = 24; + const customHeight = 20; + const section: Section = { id: 'section1', kind: 'dashboard', order: 10 }; + const staticViz: Content = { + id: 'content1', + kind: 'visualization', + order: 0, + width: customWidth, + height: customHeight, + input: { + kind: 'static', + id: 'viz-id-static', + }, + }; + + const clientMock = coreMock.createStart().savedObjects.client; + const input = await createDashboardInput(section, [staticViz], { + savedObjectsClient: clientMock, + }); + + expect(input.panels).toEqual({ + content1: { + explicitInput: { + disabledActions: ['togglePanel'], + id: 'content1', + savedObjectId: 'viz-id-static', + }, + gridData: { + i: 'content1', + h: customHeight, + w: customWidth, + x: 0, + y: 0, + }, + type: 'visualization', + }, + }); +}); + +test('it uses default width if custom content width is <= 0', async () => { + const customWidthShouldBeBiggerThan0 = 0; + const section: Section = { id: 'section1', kind: 'dashboard', order: 10 }; + const staticViz: Content = { + id: 'content1', + kind: 'visualization', + order: 0, + width: customWidthShouldBeBiggerThan0, + input: { + kind: 'static', + id: 'viz-id-static', + }, + }; + + const clientMock = coreMock.createStart().savedObjects.client; + const input = await createDashboardInput(section, [staticViz], { + savedObjectsClient: clientMock, + }); + + expect(input.panels).toEqual({ + content1: { + explicitInput: { + disabledActions: ['togglePanel'], + id: 'content1', + savedObjectId: 'viz-id-static', + }, + gridData: { + h: 15, + i: 'content1', + w: DASHBOARD_PANEL_WIDTH, + x: 0, + y: 0, + }, + type: 'visualization', + }, + }); +}); + +test('it should use default width if custom content width > DASHBOARD_GRID_COLUMN_COUNT: 48', async () => { + const customWidthShouldNotBeBiggerThan0 = 49; + const section: Section = { id: 'section1', kind: 'dashboard', order: 10 }; + const staticViz: Content = { + id: 'content1', + kind: 'visualization', + order: 0, + width: customWidthShouldNotBeBiggerThan0, + input: { + kind: 'static', + id: 'viz-id-static', + }, + }; + + const clientMock = coreMock.createStart().savedObjects.client; + const input = await createDashboardInput(section, [staticViz], { + savedObjectsClient: clientMock, + }); + + expect(input.panels).toEqual({ + content1: { + explicitInput: { + disabledActions: ['togglePanel'], + id: 'content1', + savedObjectId: 'viz-id-static', + }, + gridData: { + h: 15, + i: 'content1', + w: DASHBOARD_PANEL_WIDTH, + x: 0, + y: 0, + }, + type: 'visualization', + }, + }); +}); diff --git a/src/plugins/content_management/public/components/section_input.ts b/src/plugins/content_management/public/components/section_input.ts index 5a0b9ca370c6..7d49f8a17ef9 100644 --- a/src/plugins/content_management/public/components/section_input.ts +++ b/src/plugins/content_management/public/components/section_input.ts @@ -14,6 +14,8 @@ import { CARD_EMBEDDABLE } from './card_container/card_embeddable'; import { CardContainerInput } from './card_container/types'; const DASHBOARD_GRID_COLUMN_COUNT = 48; +export const DASHBOARD_PANEL_WIDTH = 12; +export const DASHBOARD_PANEL_HEIGHT = 15; export const createCardInput = ( section: Section, @@ -31,6 +33,7 @@ export const createCardInput = ( hidePanelTitles: true, viewMode: ViewMode.VIEW, columns: section.columns, + wrap: section.wrap, panels, ...section.input, }; @@ -71,12 +74,26 @@ export const createDashboardInput = async ( const panels: DashboardContainerInput['panels'] = {}; let x = 0; let y = 0; - const w = 12; - const h = 15; const counter = new BehaviorSubject(0); contents.forEach(async (content) => { counter.next(counter.value + 1); + + let w = DASHBOARD_PANEL_WIDTH; + let h = DASHBOARD_PANEL_HEIGHT; + + if ('width' in content && typeof content.width === 'number') { + if (content.width > 0 && content.width <= DASHBOARD_GRID_COLUMN_COUNT) { + w = content.width; + } + } + + if ('height' in content && typeof content.height === 'number') { + if (content.height > 0) { + h = content.height; + } + } + try { if (content.kind === 'dashboard') { let dashboardId = ''; @@ -120,7 +137,13 @@ export const createDashboardInput = async ( return; } - const config: DashboardContainerInput['panels'][string] = { + // If current panel exceed the max dashboard container width, add the panel to the next row + if (x + w > DASHBOARD_GRID_COLUMN_COUNT) { + x = 0; + y = y + h; + } + + const panelConfig: DashboardContainerInput['panels'][string] = { gridData: { w, h, @@ -135,28 +158,25 @@ export const createDashboardInput = async ( }, }; + // The new x starts from the current panel x + current panel width x = x + w; - if (x >= DASHBOARD_GRID_COLUMN_COUNT) { - x = 0; - y = y + h; - } if (content.kind === 'visualization') { - config.type = 'visualization'; + panelConfig.type = 'visualization'; if (content.input.kind === 'dynamic') { - config.explicitInput.savedObjectId = await content.input.get(); + panelConfig.explicitInput.savedObjectId = await content.input.get(); } if (content.input.kind === 'static') { - config.explicitInput.savedObjectId = content.input.id; + panelConfig.explicitInput.savedObjectId = content.input.id; } } if (content.kind === 'custom') { - config.type = CUSTOM_CONTENT_EMBEDDABLE; - config.explicitInput.render = content.render; + panelConfig.type = CUSTOM_CONTENT_EMBEDDABLE; + panelConfig.explicitInput.render = content.render; } - panels[content.id] = config; + panels[content.id] = panelConfig; } catch (e) { // eslint-disable-next-line console.log(e); diff --git a/src/plugins/content_management/public/services/content_management/types.ts b/src/plugins/content_management/public/services/content_management/types.ts index 5b9b4662d37f..755e6f426a0a 100644 --- a/src/plugins/content_management/public/services/content_management/types.ts +++ b/src/plugins/content_management/public/services/content_management/types.ts @@ -35,8 +35,9 @@ export type Section = id: string; order: number; title?: string; - columns?: number; input?: CardContainerExplicitInput; + columns?: number; + wrap?: boolean; }; export type Content = @@ -45,18 +46,24 @@ export type Content = id: string; order: number; input: SavedObjectInput; + width?: number; + height?: number; } | { kind: 'dashboard'; id: string; order: number; input: SavedObjectInput; + width?: number; + height?: number; } | { kind: 'custom'; id: string; order: number; render: () => JSX.Element; + width?: number; + height?: number; } | { kind: 'card'; From a7b08e83d5c56e8151421b20de048e9327a41450 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:12:42 +0800 Subject: [PATCH 217/276] [Workspace] Support workspace initial page (#7708) (#7767) * Support workspace initial page * Changeset file for PR #7708 created/updated * optimzie the code * fix the test error * add dark mode svg url --------- (cherry picked from commit 9aeebec4ffa8a997c6eab39dabf74f842568d64e) Signed-off-by: yubonluo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7708.yml | 2 + src/plugins/workspace/common/constants.ts | 1 + src/plugins/workspace/public/application.tsx | 19 +- .../public/assets/background_dark.svg | 363 ++++++ .../public/assets/background_light.svg | 363 ++++++ .../workspace_initial.test.tsx.snap | 1048 +++++++++++++++++ .../workspace_initial.test.tsx | 53 + .../workspace_initial/workspace_initial.tsx | 237 ++++ .../components/workspace_initial_app.tsx | 16 + src/plugins/workspace/public/plugin.test.ts | 19 +- src/plugins/workspace/public/plugin.ts | 15 + src/plugins/workspace/server/plugin.test.ts | 57 + src/plugins/workspace/server/plugin.ts | 23 + .../workspace/server/routes/duplicate.ts | 1 - src/plugins/workspace/server/routes/index.ts | 5 - src/plugins/workspace/server/types.ts | 1 - 16 files changed, 2211 insertions(+), 12 deletions(-) create mode 100644 changelogs/fragments/7708.yml create mode 100644 src/plugins/workspace/public/assets/background_dark.svg create mode 100644 src/plugins/workspace/public/assets/background_light.svg create mode 100644 src/plugins/workspace/public/components/workspace_initial/__snapshots__/workspace_initial.test.tsx.snap create mode 100644 src/plugins/workspace/public/components/workspace_initial/workspace_initial.test.tsx create mode 100644 src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx create mode 100644 src/plugins/workspace/public/components/workspace_initial_app.tsx diff --git a/changelogs/fragments/7708.yml b/changelogs/fragments/7708.yml new file mode 100644 index 000000000000..56ead27a3644 --- /dev/null +++ b/changelogs/fragments/7708.yml @@ -0,0 +1,2 @@ +feat: +- Support workspace initial page ([#7708](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7708)) \ No newline at end of file diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index 5eae709784f3..c8582d2439de 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -10,6 +10,7 @@ export const WORKSPACE_FATAL_ERROR_APP_ID = 'workspace_fatal_error'; export const WORKSPACE_CREATE_APP_ID = 'workspace_create'; export const WORKSPACE_LIST_APP_ID = 'workspace_list'; export const WORKSPACE_DETAIL_APP_ID = 'workspace_detail'; +export const WORKSPACE_INITIAL_APP_ID = 'workspace_initial'; /** * Since every workspace always have overview and update page, these features will be selected by default * and can't be changed in the workspace form feature selector diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index 31965012d16c..cbc45c938586 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -5,7 +5,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; +import { HashRouter as Router, Route, Switch } from 'react-router-dom'; import { AppMountParameters, ScopedHistory } from '../../../core/public'; import { OpenSearchDashboardsContextProvider } from '../../opensearch_dashboards_react/public'; import { WorkspaceFatalError } from './components/workspace_fatal_error'; @@ -15,7 +15,7 @@ import { Services } from './types'; import { WorkspaceCreatorProps } from './components/workspace_creator/workspace_creator'; import { WorkspaceDetailApp } from './components/workspace_detail_app'; import { WorkspaceDetailProps } from './components/workspace_detail/workspace_detail'; -import { DetailTab } from './components/workspace_form/constants'; +import { WorkspaceInitialApp } from './components/workspace_initial_app'; export const renderCreatorApp = ( { element }: AppMountParameters, @@ -87,3 +87,18 @@ export const renderDetailApp = ( ReactDOM.unmountComponentAtNode(element); }; }; + +export const renderInitialApp = ({}: AppMountParameters, services: Services) => { + const rootElement = document.getElementById('opensearch-dashboards-body'); + + ReactDOM.render( + + + , + rootElement + ); + + return () => { + ReactDOM.unmountComponentAtNode(rootElement!); + }; +}; diff --git a/src/plugins/workspace/public/assets/background_dark.svg b/src/plugins/workspace/public/assets/background_dark.svg new file mode 100644 index 000000000000..0e6de636d08d --- /dev/null +++ b/src/plugins/workspace/public/assets/background_dark.svg @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/plugins/workspace/public/assets/background_light.svg b/src/plugins/workspace/public/assets/background_light.svg new file mode 100644 index 000000000000..7e33b6ceff7f --- /dev/null +++ b/src/plugins/workspace/public/assets/background_light.svg @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/plugins/workspace/public/components/workspace_initial/__snapshots__/workspace_initial.test.tsx.snap b/src/plugins/workspace/public/components/workspace_initial/__snapshots__/workspace_initial.test.tsx.snap new file mode 100644 index 000000000000..2c2b25a1e116 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_initial/__snapshots__/workspace_initial.test.tsx.snap @@ -0,0 +1,1048 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`WorkspaceInitial render workspace initial page normally when theme is dark mode 1`] = ` +
    +
    +
    +
    +
    +
    + OpenSearch +
    +
    +
    +
    +
    +
    +
    +

    + Getting started with OpenSearch +

    +
    +
    +
    + OpenSearch is a flexible, scalable, open-source way to build solutions for data-intensive search and analytics applications. Explore, enrich, and visualize your data, using developer-friendly tools and powerful integrations for machine learning, data processing, and more. +
    +
    + +
    +
    +
    + +   Explore live demo environment at + + + playground.opensearch.org + +
    +
    +
    +
    +
    +
    +
    +
    + + Create a workspace + +
    +

    + + Organize projects by use case in a collaborative workspace. + +

    +
    +
    + +
    +
    +
    +
    +
    + + Try OpenSearch + +
    +

    + Explore sample data before adding your own. +

    +
    +
    + +
    +
    +
    +
    +
    + + Add your data + +
    +

    + Start collecting and analyzing your data. +

    +
    +
    + +
    +
    +
    +
    +
    + + Discover insights + +
    +

    + Explore data interactively to uncover insights. +

    +
    +
    + +
    +
    +
    +
    +
    + +
    +

    + And much more... +

    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +`; + +exports[`WorkspaceInitial render workspace initial page normally when user is dashboard admin 1`] = ` +
    +
    +
    +
    +
    +
    + OpenSearch +
    +
    +
    +
    +
    +
    +
    +

    + Getting started with OpenSearch +

    +
    +
    +
    + OpenSearch is a flexible, scalable, open-source way to build solutions for data-intensive search and analytics applications. Explore, enrich, and visualize your data, using developer-friendly tools and powerful integrations for machine learning, data processing, and more. +
    +
    + +
    +
    +
    + +   Explore live demo environment at + + + playground.opensearch.org + +
    +
    +
    +
    +
    +
    +
    +
    + + Create a workspace + +
    +

    + + Organize projects by use case in a collaborative workspace. + +

    +
    +
    + +
    +
    +
    +
    +
    + + Try OpenSearch + +
    +

    + Explore sample data before adding your own. +

    +
    +
    + +
    +
    +
    +
    +
    + + Add your data + +
    +

    + Start collecting and analyzing your data. +

    +
    +
    + +
    +
    +
    +
    +
    + + Discover insights + +
    +

    + Explore data interactively to uncover insights. +

    +
    +
    + +
    +
    +
    +
    +
    + +
    +

    + And much more... +

    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +`; + +exports[`WorkspaceInitial render workspace initial page normally when user is non dashboard admin 1`] = ` +
    +
    +
    +
    +
    +
    + OpenSearch +
    +
    +
    +
    +
    +
    +
    +

    + Getting started with OpenSearch +

    +
    +
    +
    + OpenSearch is a flexible, scalable, open-source way to build solutions for data-intensive search and analytics applications. Explore, enrich, and visualize your data, using developer-friendly tools and powerful integrations for machine learning, data processing, and more. +
    +
    + +
    +
    +
    + +   Explore live demo environment at + + + playground.opensearch.org + +
    +
    +
    +
    +
    +
    +
    +
    + + Create a workspace + +
    +

    + + Organize projects by use case in a collaborative workspace. + +

    +
    +
    +
    +
    +
    +
    +
    + + Try OpenSearch + +
    +

    + Explore sample data before adding your own. +

    +
    +
    + +
    +
    +
    +
    +
    + + Add your data + +
    +

    + Start collecting and analyzing your data. +

    +
    +
    + +
    +
    +
    +
    +
    + + Discover insights + +
    +

    + Explore data interactively to uncover insights. +

    +
    +
    + +
    +
    +
    +
    +
    + +
    +

    + And much more... +

    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +`; diff --git a/src/plugins/workspace/public/components/workspace_initial/workspace_initial.test.tsx b/src/plugins/workspace/public/components/workspace_initial/workspace_initial.test.tsx new file mode 100644 index 000000000000..698a4c109cfd --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_initial/workspace_initial.test.tsx @@ -0,0 +1,53 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { render } from '@testing-library/react'; +import React from 'react'; +import { WorkspaceInitial } from './workspace_initial'; +import { coreMock } from '../../../../../core/public/mocks'; +import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; + +const mockCoreStart = coreMock.createStart(); +const WorkspaceInitialPage = (props: { isDashboardAdmin: boolean }) => { + const { isDashboardAdmin } = props; + const { Provider } = createOpenSearchDashboardsReactContext({ + ...mockCoreStart, + ...{ + application: { + ...mockCoreStart.application, + capabilities: { + ...mockCoreStart.application.capabilities, + dashboards: { + isDashboardAdmin, + }, + }, + }, + }, + }); + + return ( + + + + ); +}; + +describe('WorkspaceInitial', () => { + it('render workspace initial page normally when user is dashboard admin', async () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('render workspace initial page normally when user is non dashboard admin', async () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it('render workspace initial page normally when theme is dark mode', async () => { + mockCoreStart.uiSettings.get.mockReturnValue(true); + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx b/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx new file mode 100644 index 000000000000..7d88210820f4 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx @@ -0,0 +1,237 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { + EuiLink, + EuiPage, + EuiIcon, + EuiText, + EuiCard, + EuiImage, + EuiPanel, + EuiTitle, + EuiSpacer, + EuiPageBody, + EuiFlexItem, + EuiFlexGroup, + EuiButtonEmpty, + EuiPageContent, + EuiSmallButton, + EuiToolTip, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import BackgroundLightSVG from '../../assets/background_light.svg'; +import BackgroundDarkSVG from '../../assets/background_light.svg'; +import { WORKSPACE_CREATE_APP_ID } from '../../../common/constants'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; + +export const WorkspaceInitial = () => { + const { + services: { application, chrome, uiSettings }, + } = useOpenSearchDashboards(); + const isDashboardAdmin = application.capabilities.dashboards?.isDashboardAdmin; + const logos = chrome.logos; + const createWorkspaceUrl = application.getUrlForApp(WORKSPACE_CREATE_APP_ID, { absolute: true }); + const settingsAndSetupUrl = application.getUrlForApp('settings_landing', { absolute: true }); + const isDarkTheme = uiSettings.get('theme:darkMode'); + const backGroundUrl = isDarkTheme ? BackgroundDarkSVG : BackgroundLightSVG; + + const noAdminToolTip = i18n.translate('workspace.initial.card.createWorkspace.toolTip', { + defaultMessage: + 'Contact your administrator to create a workspace or to be added to an existing one.', + }); + + const createButton = ( + + {i18n.translate('workspace.initial.card.createWorkspace.button', { + defaultMessage: 'Create Workspace', + })} + + ); + + const cards = ( + + + + <> + {i18n.translate('workspace.initial.card.createWorkspace.description', { + defaultMessage: 'Organize projects by use case in a collaborative workspace.', + })} + + + } + footer={isDashboardAdmin && createButton} + /> + + + + {i18n.translate('workspace.initial.card.tryOpenSearch.footer', { + defaultMessage: 'with Sample Datasets', + })} + + } + /> + + + + {i18n.translate('workspace.initial.card.addData.footer', { + defaultMessage: 'with Getting Started Guide', + })} + + } + /> + + + + {i18n.translate('workspace.initial.card.discoverInsights.footer', { + defaultMessage: 'with Discover', + })} + + } + /> + + + + + + ); + + const content = ( + + + +

    + {i18n.translate('workspace.initial.title', { + defaultMessage: 'Getting started with OpenSearch', + })} +

    +
    +
    + + + {i18n.translate('workspace.initial.description', { + defaultMessage: + 'OpenSearch is a flexible, scalable, open-source way to build solutions for data-intensive search and analytics applications. Explore, enrich, and visualize your data, using developer-friendly tools and powerful integrations for machine learning, data processing, and more.', + })} + + + + + + {i18n.translate('workspace.initial.button.openSearch', { + defaultMessage: 'Learn more from documentation and more.', + })} + + + + + + + + +   Explore live demo environment at{' '} + playground.opensearch.org + + + + {cards} +
    + ); + + return ( + + + + + + + + + + {content} + + + + {i18n.translate('workspace.initial.button.settingsAndSetup', { + defaultMessage: 'Settings and setup', + })} + + + + + + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_initial_app.tsx b/src/plugins/workspace/public/components/workspace_initial_app.tsx new file mode 100644 index 000000000000..553a41cb5110 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_initial_app.tsx @@ -0,0 +1,16 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { I18nProvider } from '@osd/i18n/react'; +import { WorkspaceInitial } from './workspace_initial/workspace_initial'; + +export const WorkspaceInitialApp = () => { + return ( + + + + ); +}; diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 2fc7d41b50ca..41f779911876 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -40,7 +40,7 @@ describe('Workspace plugin', () => { savedObjectsManagement: savedObjectManagementSetupMock, management: managementPluginMock.createSetupContract(), }); - expect(setupMock.application.register).toBeCalledTimes(4); + expect(setupMock.application.register).toBeCalledTimes(5); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(savedObjectManagementSetupMock.columns.register).toBeCalledTimes(1); }); @@ -53,7 +53,7 @@ describe('Workspace plugin', () => { workspacePlugin.start(coreStart, mockDependencies); coreStart.workspaces.currentWorkspaceId$.next('foo'); expect(coreStart.savedObjects.client.setCurrentWorkspace).toHaveBeenCalledWith('foo'); - expect(setupMock.application.register).toBeCalledTimes(4); + expect(setupMock.application.register).toBeCalledTimes(5); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(workspaceClientMock.enterWorkspace).toBeCalledTimes(0); }); @@ -90,7 +90,7 @@ describe('Workspace plugin', () => { await workspacePlugin.setup(setupMock, { management: managementPluginMock.createSetupContract(), }); - expect(setupMock.application.register).toBeCalledTimes(4); + expect(setupMock.application.register).toBeCalledTimes(5); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(workspaceClientMock.enterWorkspace).toBeCalledWith('workspaceId'); expect(setupMock.getStartServices).toBeCalledTimes(2); @@ -202,6 +202,19 @@ describe('Workspace plugin', () => { ); }); + it('#setup should register workspace initial with a visible application', async () => { + const setupMock = coreMock.createSetup(); + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, {}); + + expect(setupMock.application.register).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'workspace_initial', + navLinkStatus: AppNavLinkStatus.hidden, + }) + ); + }); + it('#start add workspace detail page to breadcrumbs when start', async () => { const startMock = coreMock.createStart(); const workspaceObject = { diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index cdebba4afa99..d19ceee6270f 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -30,6 +30,7 @@ import { WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID, WORKSPACE_USE_CASES, + WORKSPACE_INITIAL_APP_ID, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; import { Services, WorkspaceUseCase } from './types'; @@ -358,6 +359,20 @@ export class WorkspacePlugin }, }); + // workspace initial page + core.application.register({ + id: WORKSPACE_INITIAL_APP_ID, + title: i18n.translate('workspace.settings.workspaceInitial', { + defaultMessage: 'Workspace Initial', + }), + navLinkStatus: AppNavLinkStatus.hidden, + async mount(params: AppMountParameters) { + const { renderInitialApp } = await import('./application'); + return mountWorkspaceApp(params, renderInitialApp); + }, + workspaceAvailability: WorkspaceAvailability.outsideWorkspace, + }); + // workspace list core.application.register({ id: WORKSPACE_LIST_APP_ID, diff --git a/src/plugins/workspace/server/plugin.test.ts b/src/plugins/workspace/server/plugin.test.ts index e3e094b94a46..d5aad60ac88d 100644 --- a/src/plugins/workspace/server/plugin.test.ts +++ b/src/plugins/workspace/server/plugin.test.ts @@ -176,6 +176,63 @@ describe('Workspace server plugin', () => { }); }); + describe('#setUpRedirectPage', () => { + const setupMock = coreMock.createSetup(); + const initializerContextConfigMock = coreMock.createPluginInitializerContext({ + enabled: true, + permission: { + enabled: true, + }, + }); + let registerOnPostAuthFn: OnPostAuthHandler = () => httpServerMock.createResponseFactory().ok(); + setupMock.http.registerOnPostAuth.mockImplementation((fn) => { + registerOnPostAuthFn = fn; + return fn; + }); + const workspacePlugin = new WorkspacePlugin(initializerContextConfigMock); + const response = httpServerMock.createResponseFactory(); + + it('with / request path', async () => { + const request = httpServerMock.createOpenSearchDashboardsRequest({ + path: '/', + }); + await workspacePlugin.setup(setupMock); + const toolKitMock = httpServerMock.createToolkit(); + + await registerOnPostAuthFn(request, response, toolKitMock); + expect(response.redirected).toBeCalledWith({ + headers: { location: '/mock-server-basepath/app/workspace_initial' }, + }); + }); + + it('without / request path', async () => { + const request = httpServerMock.createOpenSearchDashboardsRequest({ + path: '/foo', + }); + await workspacePlugin.setup(setupMock); + const toolKitMock = httpServerMock.createToolkit(); + + await registerOnPostAuthFn(request, response, toolKitMock); + expect(toolKitMock.next).toBeCalledTimes(1); + }); + + it('with more than one workspace', async () => { + const request = httpServerMock.createOpenSearchDashboardsRequest({ + path: '/', + }); + const workspaceSetup = await workspacePlugin.setup(setupMock); + const client = workspaceSetup.client; + jest.spyOn(client, 'list').mockResolvedValue({ + success: true, + result: { total: 1 }, + }); + const toolKitMock = httpServerMock.createToolkit(); + + await registerOnPostAuthFn(request, response, toolKitMock); + expect(toolKitMock.next).toBeCalledTimes(1); + }); + }); + it('#start', async () => { const setupMock = coreMock.createSetup(); const startMock = coreMock.createStart(); diff --git a/src/plugins/workspace/server/plugin.ts b/src/plugins/workspace/server/plugin.ts index 6e7a29322aa0..6d9c46ed9dc8 100644 --- a/src/plugins/workspace/server/plugin.ts +++ b/src/plugins/workspace/server/plugin.ts @@ -22,6 +22,7 @@ import { PRIORITY_FOR_PERMISSION_CONTROL_WRAPPER, WORKSPACE_UI_SETTINGS_CLIENT_WRAPPER_ID, PRIORITY_FOR_WORKSPACE_UI_SETTINGS_WRAPPER, + WORKSPACE_INITIAL_APP_ID, } from '../common/constants'; import { IWorkspaceClientImpl, WorkspacePluginSetup, WorkspacePluginStart } from './types'; import { WorkspaceClient } from './workspace_client'; @@ -108,6 +109,26 @@ export class WorkspacePlugin implements Plugin { + const path = request.url.pathname; + if (path === '/') { + const workspaceListResponse = await this.client?.list( + { request, logger: this.logger }, + { page: 1, perPage: 1 } + ); + if (workspaceListResponse?.success && workspaceListResponse.result.total > 0) { + return toolkit.next(); + } + const basePath = core.http.basePath.serverBasePath; + return response.redirected({ + headers: { location: `${basePath}/app/${WORKSPACE_INITIAL_APP_ID}` }, + }); + } + return toolkit.next(); + }); + } + constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get(); this.globalConfig$ = initializerContext.config.legacy.globalConfig$; @@ -172,6 +193,8 @@ export class WorkspacePlugin implements Plugin { const result = await client.list( { - context, request: req, logger, }, @@ -139,7 +138,6 @@ export function registerRoutes({ const { id } = req.params; const result = await client.get( { - context, request: req, logger, }, @@ -183,7 +181,6 @@ export function registerRoutes({ const result = await client.create( { - context, request: req, logger, }, @@ -211,7 +208,6 @@ export function registerRoutes({ const result = await client.update( { - context, request: req, logger, }, @@ -239,7 +235,6 @@ export function registerRoutes({ const result = await client.delete( { - context, request: req, logger, }, diff --git a/src/plugins/workspace/server/types.ts b/src/plugins/workspace/server/types.ts index 5e88e5acb3ae..b21f31e3accd 100644 --- a/src/plugins/workspace/server/types.ts +++ b/src/plugins/workspace/server/types.ts @@ -32,7 +32,6 @@ export interface WorkspaceFindOptions { export interface IRequestDetail { request: OpenSearchDashboardsRequest; - context: RequestHandlerContext; logger: Logger; } From 30791d80d921002e982fed2c6f4e21851bc28a88 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:21:22 +0800 Subject: [PATCH 218/276] [Workspace]fix the parameter misalignment error in the workspace_detail_page (#7768) (#7772) * fix the argument error in the workspace_detail_page * Changeset file for PR #7768 created/updated --------- (cherry picked from commit b46a34dce34528ff6034c6282078552f578c5181) Signed-off-by: Qxisylolo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7768.yml | 2 ++ .../public/components/workspace_detail/workspace_detail.tsx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/7768.yml diff --git a/changelogs/fragments/7768.yml b/changelogs/fragments/7768.yml new file mode 100644 index 000000000000..ac0418eb42b0 --- /dev/null +++ b/changelogs/fragments/7768.yml @@ -0,0 +1,2 @@ +fix: +- Fix the parameter misalignment in the workspace_detail_page ([#7768](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7768)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx index a95756947424..6e3e628e4538 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail.tsx @@ -187,7 +187,7 @@ export const WorkspaceDetail = (props: WorkspaceDetailProps) => { {deletedWorkspace && ( setDeletedWorkspace(null)} onDeleteSuccess={() => { window.setTimeout(() => { From 63723a5700c92c303341ce207595545c14747119 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 08:35:34 -0700 Subject: [PATCH 219/276] Add Application Page Header for Visualize Pages (#7712) (#7778) * Add Application Header for Visualize * Fix Application Header Layout for Discover * Changeset file for PR #7712 created/updated * Add new Page Header in Vis Builder --------- (cherry picked from commit b3234ddd9f8ad01137ca8bdcc7ee5fd4314d7993) Signed-off-by: Suchit Sahoo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7712.yml | 2 + .../dashboard_listing/dashboard_listing.tsx | 63 +- .../public/components/app_container.tsx | 12 +- .../view_components/canvas/top_nav.tsx | 2 +- .../table_list_view/table_list_view.tsx | 21 +- .../vis_builder/public/application/app.tsx | 13 + .../public/application/components/top_nav.tsx | 47 +- .../application/utils/get_top_nav_config.tsx | 176 ++++-- .../visualize/public/application/app.tsx | 1 + .../components/visualize_byvalue_editor.tsx | 12 + .../components/visualize_editor.tsx | 12 + .../components/visualize_listing.tsx | 97 +++- .../components/visualize_top_nav.tsx | 86 ++- .../public/application/utils/constants.ts | 18 + .../application/utils/get_top_nav_config.tsx | 540 ++++++++++++------ 15 files changed, 771 insertions(+), 331 deletions(-) create mode 100644 changelogs/fragments/7712.yml create mode 100644 src/plugins/visualize/public/application/utils/constants.ts diff --git a/changelogs/fragments/7712.yml b/changelogs/fragments/7712.yml new file mode 100644 index 000000000000..faba262bcc6b --- /dev/null +++ b/changelogs/fragments/7712.yml @@ -0,0 +1,2 @@ +feat: +- Add New Page Header to Visualize ([#7712](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7712)) \ No newline at end of file diff --git a/src/plugins/dashboard/public/application/components/dashboard_listing/dashboard_listing.tsx b/src/plugins/dashboard/public/application/components/dashboard_listing/dashboard_listing.tsx index 00ce5a713b7f..e145f397d4c0 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_listing/dashboard_listing.tsx +++ b/src/plugins/dashboard/public/application/components/dashboard_listing/dashboard_listing.tsx @@ -34,6 +34,7 @@ export const DashboardListing = () => { dashboardProviders, data: { query }, osdUrlStateStorage, + navigation, }, } = useOpenSearchDashboards(); @@ -41,6 +42,9 @@ export const DashboardListing = () => { const queryParameters = useMemo(() => new URLSearchParams(location.search), [location]); const initialFiltersFromURL = queryParameters.get('filter'); const [initialFilter, setInitialFilter] = useState(initialFiltersFromURL); + const showUpdatedUx = uiSettings?.get('home:useNewHomePage'); + const { HeaderControl } = navigation.ui; + const { setAppRightControls } = application; useEffect(() => { // syncs `_g` portion of url with query services @@ -201,31 +205,40 @@ export const DashboardListing = () => { ); }); + const createButton = ; + return ( - - } - findItems={find} - deleteItems={hideWriteControls ? undefined : deleteItems} - editItem={hideWriteControls ? undefined : editItem} - tableColumns={tableColumns} - listingLimit={listingLimit} - initialFilter={initialFilter ?? ''} - initialPageSize={initialPageSize} - noItemsFragment={noItemsFragment} - entityName={i18n.translate('dashboard.listing.table.entityName', { - defaultMessage: 'dashboard', - })} - entityNamePlural={i18n.translate('dashboard.listing.table.entityNamePlural', { - defaultMessage: 'dashboards', - })} - tableListTitle={i18n.translate('dashboard.listing.dashboardsTitle', { - defaultMessage: 'Dashboards', - })} - toastNotifications={notifications.toasts} - /> + <> + {showUpdatedUx && !hideWriteControls && ( + + )} + + ); }; diff --git a/src/plugins/data_explorer/public/components/app_container.tsx b/src/plugins/data_explorer/public/components/app_container.tsx index d3dc6a97ef0d..b8749bf914e2 100644 --- a/src/plugins/data_explorer/public/components/app_container.tsx +++ b/src/plugins/data_explorer/public/components/app_container.tsx @@ -31,6 +31,7 @@ export const AppContainer = React.memo( const opensearchDashboards = useOpenSearchDashboards(); const { uiSettings } = opensearchDashboards.services; const isEnhancementsEnabled = uiSettings?.get(QUERY_ENHANCEMENT_ENABLED_SETTING); + const showActionsInGroup = uiSettings?.get('home:useNewHomePage'); const topLinkRef = useRef(null); const datePickerRef = useRef(null); @@ -47,21 +48,22 @@ export const AppContainer = React.memo( topLinkRef, datePickerRef, }; - // Render the application DOM. return (
    {isEnhancementsEnabled && ( - -
    - + {!showActionsInGroup && ( + +
    + + )}
    diff --git a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx index fa3ee3524994..8c4f748ca060 100644 --- a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx @@ -126,6 +126,7 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro <> {isEnhancementsEnabled && !!opts?.optionalRef?.topLinkRef?.current && + !showActionsInGroup && createPortal( {topNavLinks.map((topNavLink) => ( @@ -145,7 +146,6 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro opts.optionalRef.topLinkRef.current )} {this.state.showDeleteModal && this.renderConfirmDeleteModal()} - - - -

    {this.props.tableListTitle}

    -
    -
    - - {this.props.createButton || defaultCreateButton} -
    + {!this.props.showUpdatedUx && ( + + + +

    {this.props.tableListTitle}

    +
    +
    + + {this.props.createButton || defaultCreateButton} +
    + )} diff --git a/src/plugins/vis_builder/public/application/app.tsx b/src/plugins/vis_builder/public/application/app.tsx index 9a3367651fc2..515567ddcc4c 100644 --- a/src/plugins/vis_builder/public/application/app.tsx +++ b/src/plugins/vis_builder/public/application/app.tsx @@ -15,6 +15,7 @@ import { RightNav } from './components/right_nav'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; import { VisBuilderServices } from '../types'; import { syncQueryStateWithUrl } from '../../../data/public'; +import { HeaderVariant } from '../../../../core/public/index'; import './app.scss'; @@ -23,9 +24,21 @@ export const VisBuilderApp = () => { services: { data: { query }, osdUrlStateStorage, + chrome, + uiSettings, }, } = useOpenSearchDashboards(); const { pathname } = useLocation(); + const { setHeaderVariant } = chrome; + const showActionsInGroup = uiSettings.get('home:useNewHomePage'); + + useEffect(() => { + if (showActionsInGroup) setHeaderVariant?.(HeaderVariant.APPLICATION); + + return () => { + setHeaderVariant?.(); + }; + }, [setHeaderVariant, showActionsInGroup]); useEffect(() => { // syncs `_g` portion of url with query services diff --git a/src/plugins/vis_builder/public/application/components/top_nav.tsx b/src/plugins/vis_builder/public/application/components/top_nav.tsx index 8361073bcd14..3e8ff11254f7 100644 --- a/src/plugins/vis_builder/public/application/components/top_nav.tsx +++ b/src/plugins/vis_builder/public/application/components/top_nav.tsx @@ -8,7 +8,7 @@ import { isEqual } from 'lodash'; import { useParams } from 'react-router-dom'; import { useUnmount } from 'react-use'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { getTopNavConfig } from '../utils/get_top_nav_config'; +import { getLegacyTopNavConfig, getNavActions, getTopNavConfig } from '../utils/get_top_nav_config'; import { VisBuilderServices } from '../../types'; import './top_nav.scss'; @@ -18,7 +18,7 @@ import { setSavedQuery } from '../utils/state_management/visualization_slice'; import { setEditorState } from '../utils/state_management/metadata_slice'; import { useCanSave } from '../utils/use/use_can_save'; import { saveStateToSavedObject } from '../../saved_visualizations/transforms'; -import { TopNavMenuData } from '../../../../navigation/public'; +import { TopNavMenuData, TopNavMenuItemRenderType } from '../../../../navigation/public'; import { opensearchFilters, connectStorageToQueryState } from '../../../../data/public'; import { RootState } from '../../../../data_explorer/public'; @@ -41,11 +41,13 @@ export const TopNav = () => { navigation: { ui: { TopNavMenu }, }, + uiSettings, appName, capabilities, } = services; const rootState = useTypedSelector((state: RootState) => state); const dispatch = useTypedDispatch(); + const showActionsInGroup = uiSettings.get('home:useNewHomePage'); useDeepEffect(() => { dispatch(setEditorState({ state: 'dirty' })); @@ -67,7 +69,7 @@ export const TopNav = () => { const getConfig = () => { if (!savedVisBuilderVis || !indexPattern) return; - return getTopNavConfig( + const navActions = getNavActions( { visualizationIdFromUrl, savedVisBuilderVis: saveStateToSavedObject(savedVisBuilderVis, rootState, indexPattern), @@ -77,6 +79,38 @@ export const TopNav = () => { }, services ); + + return showActionsInGroup + ? getTopNavConfig( + { + visualizationIdFromUrl, + savedVisBuilderVis: saveStateToSavedObject( + savedVisBuilderVis, + rootState, + indexPattern + ), + saveDisabledReason, + dispatch, + originatingApp, + }, + services, + navActions + ) + : getLegacyTopNavConfig( + { + visualizationIdFromUrl, + savedVisBuilderVis: saveStateToSavedObject( + savedVisBuilderVis, + rootState, + indexPattern + ), + saveDisabledReason, + dispatch, + originatingApp, + }, + services, + navActions + ); }; setConfig(getConfig()); @@ -89,6 +123,7 @@ export const TopNav = () => { dispatch, indexPattern, originatingApp, + showActionsInGroup, ]); // reset validity before component destroyed @@ -109,11 +144,15 @@ export const TopNav = () => { setMenuMountPoint={setHeaderActionMenu} indexPatterns={indexPattern ? [indexPattern] : []} showDatePicker={!!indexPattern?.timeFieldName ?? true} - showSearchBar + showSearchBar={TopNavMenuItemRenderType.IN_PORTAL} showSaveQuery={showSaveQuery} useDefaultBehaviors savedQueryId={rootState.visualization.savedQuery} onSavedQueryIdChange={updateSavedQueryId} + groupActions={showActionsInGroup} + screenTitle={ + savedVisBuilderVis?.title.length ? savedVisBuilderVis?.title : 'New visualization' + } />
    ); diff --git a/src/plugins/vis_builder/public/application/utils/get_top_nav_config.tsx b/src/plugins/vis_builder/public/application/utils/get_top_nav_config.tsx index 945e09a09734..42f3e68c3898 100644 --- a/src/plugins/vis_builder/public/application/utils/get_top_nav_config.tsx +++ b/src/plugins/vis_builder/public/application/utils/get_top_nav_config.tsx @@ -48,8 +48,11 @@ export interface TopNavConfigParams { dispatch: AppDispatch; originatingApp?: string; } +interface VisBuilderNavActionMap { + [key: string]: (anchorElement?: any) => void; +} -export const getTopNavConfig = ( +export const getLegacyTopNavConfig = ( { visualizationIdFromUrl, savedVisBuilderVis, @@ -57,15 +60,9 @@ export const getTopNavConfig = ( dispatch, originatingApp, }: TopNavConfigParams, - services: VisBuilderServices + services: VisBuilderServices, + navActions: VisBuilderNavActionMap ) => { - const { - i18n: { Context: I18nContext }, - embeddable, - } = services; - - const stateTransfer = embeddable.getStateTransfer(); - const topNavConfig: TopNavMenuData[] = [ { id: 'save', @@ -86,26 +83,7 @@ export const getTopNavConfig = ( testId: 'visBuilderSaveButton', disableButton: !!saveDisabledReason, tooltip: saveDisabledReason, - run: (_anchorElement) => { - const saveModal = ( - {}} - originatingApp={originatingApp} - getAppNameFromId={stateTransfer.getAppNameFromId} - /> - ); - - showSaveModal(saveModal, I18nContext); - }, + run: navActions.save, }, ...(originatingApp && savedVisBuilderVis && savedVisBuilderVis.id ? [ @@ -125,25 +103,7 @@ export const getTopNavConfig = ( testId: 'visBuilderSaveAndReturnButton', disableButton: !!saveDisabledReason, tooltip: saveDisabledReason, - run: async () => { - const saveOptions = { - newTitle: savedVisBuilderVis.title, - newCopyOnSave: false, - isTitleDuplicateConfirmed: false, - newDescription: savedVisBuilderVis.description, - returnToOrigin: true, - }; - - const onSave = getOnSave( - savedVisBuilderVis, - originatingApp, - visualizationIdFromUrl, - dispatch, - services - ); - - return onSave(saveOptions); - }, + run: navActions.saveAndReturn, }, ] : []), @@ -152,6 +112,61 @@ export const getTopNavConfig = ( return topNavConfig; }; +export const getTopNavConfig = ( + { + visualizationIdFromUrl, + savedVisBuilderVis, + saveDisabledReason, + dispatch, + originatingApp, + }: TopNavConfigParams, + services: VisBuilderServices, + navActions: VisBuilderNavActionMap +) => { + const topNavMenu = [ + { + tooltip: !!saveDisabledReason + ? saveDisabledReason + : savedVisBuilderVis?.id && originatingApp + ? i18n.translate('visBuilder.topNavMenu.saveVisualizationAsButtonLabel', { + defaultMessage: 'save as', + }) + : i18n.translate('visBuilder.topNavMenu.saveVisualizationButtonLabel', { + defaultMessage: 'save', + }), + ariaLabel: i18n.translate('visBuilder.topNavMenu.saveVisualizationAsButtonLabel', { + defaultMessage: 'save', + }), + testId: 'visBuilderSaveButton', + run: navActions.save, + iconType: 'save', + controlType: 'icon', + disabled: !!saveDisabledReason, + }, + ...(originatingApp && savedVisBuilderVis && savedVisBuilderVis.id + ? [ + { + tooltip: i18n.translate('visualize.topNavMenu.openInspectorTooltip', { + defaultMessage: 'Save and return', + }), + ariaLabel: i18n.translate( + 'visBuilder.topNavMenu.saveAndReturnVisualizationButtonAriaLabel', + { + defaultMessage: 'Finish editing visBuilder and return to the last app', + } + ), + testId: 'visBuilderSaveAndReturnButton', + run: navActions.saveAndReturn, + iconType: 'checkInCircleFilled', + controlType: 'icon', + disabled: !!saveDisabledReason, + }, + ] + : []), + ]; + return topNavMenu as TopNavMenuData[]; +}; + export const getOnSave = ( savedVisBuilderVis, originatingApp, @@ -258,3 +273,68 @@ export const getOnSave = ( }; return onSave; }; + +export const getNavActions = ( + { + visualizationIdFromUrl, + savedVisBuilderVis, + saveDisabledReason, + dispatch, + originatingApp, + }: TopNavConfigParams, + services: VisBuilderServices +): VisBuilderNavActionMap => { + const { + i18n: { Context: I18nContext }, + embeddable, + } = services; + + const stateTransfer = embeddable.getStateTransfer(); + + const navActions: any = {}; + + const saveAndReturnNavAction = async () => { + const saveOptions = { + newTitle: savedVisBuilderVis.title, + newCopyOnSave: false, + isTitleDuplicateConfirmed: false, + newDescription: savedVisBuilderVis.description, + returnToOrigin: true, + }; + + const onSave = getOnSave( + savedVisBuilderVis, + originatingApp, + visualizationIdFromUrl, + dispatch, + services + ); + + return onSave(saveOptions); + }; + navActions.saveAndReturn = saveAndReturnNavAction; + + const saveNavAction = (_anchorElement) => { + const saveModal = ( + {}} + originatingApp={originatingApp} + getAppNameFromId={stateTransfer.getAppNameFromId} + /> + ); + + showSaveModal(saveModal, I18nContext); + }; + + navActions.save = saveNavAction; + return navActions; +}; diff --git a/src/plugins/visualize/public/application/app.tsx b/src/plugins/visualize/public/application/app.tsx index 552fd86508e1..476d8aba05d2 100644 --- a/src/plugins/visualize/public/application/app.tsx +++ b/src/plugins/visualize/public/application/app.tsx @@ -35,6 +35,7 @@ import { Route, Switch, useLocation } from 'react-router-dom'; import { AppMountParameters } from 'opensearch-dashboards/public'; import { syncQueryStateWithUrl } from '../../../data/public'; import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; +import { HeaderVariant } from '../../../../core/public/index'; import { VisualizeServices } from './types'; import { VisualizeEditor, diff --git a/src/plugins/visualize/public/application/components/visualize_byvalue_editor.tsx b/src/plugins/visualize/public/application/components/visualize_byvalue_editor.tsx index 93a15b043c77..af52b010ae8f 100644 --- a/src/plugins/visualize/public/application/components/visualize_byvalue_editor.tsx +++ b/src/plugins/visualize/public/application/components/visualize_byvalue_editor.tsx @@ -44,6 +44,7 @@ import { import { VisualizeServices } from '../types'; import { VisualizeEditorCommon } from './visualize_editor_common'; import { VisualizeAppProps } from '../app'; +import { HeaderVariant } from '../../../../../core/public/index'; export const VisualizeByValueEditor = ({ onAppLeave }: VisualizeAppProps) => { const [originatingApp, setOriginatingApp] = useState(); @@ -52,6 +53,17 @@ export const VisualizeByValueEditor = ({ onAppLeave }: VisualizeAppProps) => { const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); const [embeddableId, setEmbeddableId] = useState(); const [valueInput, setValueInput] = useState(); + const { chrome, uiSettings } = services; + const showActionsInGroup = uiSettings.get('home:useNewHomePage'); + const { setHeaderVariant } = chrome; + + useEffect(() => { + if (showActionsInGroup) setHeaderVariant?.(HeaderVariant.APPLICATION); + + return () => { + setHeaderVariant?.(); + }; + }, [setHeaderVariant, showActionsInGroup]); useEffect(() => { const { originatingApp: value, embeddableId: embeddableIdValue, valueInput: valueInputValue } = diff --git a/src/plugins/visualize/public/application/components/visualize_editor.tsx b/src/plugins/visualize/public/application/components/visualize_editor.tsx index c7e2378a35d6..df7491fb6487 100644 --- a/src/plugins/visualize/public/application/components/visualize_editor.tsx +++ b/src/plugins/visualize/public/application/components/visualize_editor.tsx @@ -44,6 +44,7 @@ import { import { VisualizeServices } from '../types'; import { VisualizeEditorCommon } from './visualize_editor_common'; import { VisualizeAppProps } from '../app'; +import { HeaderVariant } from '../../../../../core/public/index'; export const VisualizeEditor = ({ onAppLeave }: VisualizeAppProps) => { const { id: visualizationIdFromUrl } = useParams<{ id: string }>(); @@ -51,6 +52,9 @@ export const VisualizeEditor = ({ onAppLeave }: VisualizeAppProps) => { const { services } = useOpenSearchDashboards(); const [eventEmitter] = useState(new EventEmitter()); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(!visualizationIdFromUrl); + const { chrome, uiSettings } = services; + const showActionsInGroup = uiSettings.get('home:useNewHomePage'); + const { setHeaderVariant } = chrome; const isChromeVisible = useChromeVisibility(services.chrome); const { savedVisInstance, visEditorRef, visEditorController } = useSavedVisInstance( @@ -74,6 +78,14 @@ export const VisualizeEditor = ({ onAppLeave }: VisualizeAppProps) => { ); useLinkedSearchUpdates(services, eventEmitter, appState, savedVisInstance); + useEffect(() => { + if (showActionsInGroup) setHeaderVariant?.(HeaderVariant.APPLICATION); + + return () => { + setHeaderVariant?.(); + }; + }, [setHeaderVariant, showActionsInGroup]); + useEffect(() => { const { originatingApp: value } = services.embeddable diff --git a/src/plugins/visualize/public/application/components/visualize_listing.tsx b/src/plugins/visualize/public/application/components/visualize_listing.tsx index 5dab2f11051c..ead43a7b08ca 100644 --- a/src/plugins/visualize/public/application/components/visualize_listing.tsx +++ b/src/plugins/visualize/public/application/components/visualize_listing.tsx @@ -44,6 +44,7 @@ import { VisualizeConstants } from '../visualize_constants'; import { getTableColumns, getNoItemsMessage } from '../utils'; import { getUiActions } from '../../services'; import { SAVED_OBJECT_DELETE_TRIGGER } from '../../../../saved_objects_management/public'; +import { HeaderVariant } from '../../../../../core/public/index'; export const VisualizeListing = () => { const { @@ -58,11 +59,15 @@ export const VisualizeListing = () => { savedObjectsPublic, uiSettings, visualizeCapabilities, + navigation, }, } = useOpenSearchDashboards(); const { pathname } = useLocation(); const closeNewVisModal = useRef(() => {}); const listingLimit = savedObjectsPublic.settings.getListingLimit(); + const showUpdatedUx = uiSettings?.get('home:useNewHomePage'); + const { HeaderControl } = navigation.ui; + const { setAppRightControls } = application; useEffect(() => { if (pathname === '/new') { @@ -80,13 +85,24 @@ export const VisualizeListing = () => { }, [history, pathname, visualizations]); useMount(() => { - chrome.setBreadcrumbs([ - { - text: i18n.translate('visualize.visualizeListingBreadcrumbsTitle', { - defaultMessage: 'Visualize', - }), - }, - ]); + if (showUpdatedUx) { + chrome.setBreadcrumbs([ + { + text: i18n.translate('visualize.visualizeListingBreadcrumbsTitle', { + defaultMessage: 'Visualizations', + }), + }, + ]); + } else { + chrome.setBreadcrumbs([ + { + text: i18n.translate('visualize.visualizeListingBreadcrumbsTitle', { + defaultMessage: 'Visualize', + }), + }, + ]); + } + chrome.docTitle.change( i18n.translate('visualize.listingPageTitle', { defaultMessage: 'Visualize' }) ); @@ -163,29 +179,48 @@ export const VisualizeListing = () => { ); return ( - + <> + {showUpdatedUx && ( + + )} + + ); }; diff --git a/src/plugins/visualize/public/application/components/visualize_top_nav.tsx b/src/plugins/visualize/public/application/components/visualize_top_nav.tsx index d0a1755f275e..1c3ba3bbb702 100644 --- a/src/plugins/visualize/public/application/components/visualize_top_nav.tsx +++ b/src/plugins/visualize/public/application/components/visualize_top_nav.tsx @@ -40,8 +40,9 @@ import { VisualizeEditorVisInstance, } from '../types'; import { APP_NAME } from '../visualize_constants'; -import { getTopNavConfig } from '../utils'; +import { getTopNavConfig, getNavActions, getLegacyTopNavConfig } from '../utils'; import type { IndexPattern } from '../../../../data/public'; +import { TopNavMenuItemRenderType } from '../../../../navigation/public'; interface VisualizeTopNavProps { currentAppState: VisualizeAppState; @@ -92,26 +93,66 @@ const TopNav = ({ [visInstance.embeddableHandler] ); const stateTransfer = services.embeddable.getStateTransfer(); + const showActionsInGroup = services.uiSettings.get('home:useNewHomePage'); + const navActions = getNavActions( + { + hasUnsavedChanges, + setHasUnsavedChanges, + hasUnappliedChanges, + openInspector, + originatingApp, + setOriginatingApp, + visInstance, + stateContainer, + visualizationIdFromUrl, + stateTransfer, + embeddableId, + onAppLeave, + }, + services + ); const config = useMemo(() => { if (isEmbeddableRendered) { - return getTopNavConfig( - { - hasUnsavedChanges, - setHasUnsavedChanges, - hasUnappliedChanges, - openInspector, - originatingApp, - setOriginatingApp, - visInstance, - stateContainer, - visualizationIdFromUrl, - stateTransfer, - embeddableId, - onAppLeave, - }, - services - ); + if (showActionsInGroup) { + return getTopNavConfig( + { + hasUnsavedChanges, + setHasUnsavedChanges, + hasUnappliedChanges, + openInspector, + originatingApp, + setOriginatingApp, + visInstance, + stateContainer, + visualizationIdFromUrl, + stateTransfer, + embeddableId, + onAppLeave, + }, + services, + navActions + ); + } else { + return getLegacyTopNavConfig( + { + hasUnsavedChanges, + setHasUnsavedChanges, + hasUnappliedChanges, + openInspector, + originatingApp, + setOriginatingApp, + visInstance, + stateContainer, + visualizationIdFromUrl, + stateTransfer, + embeddableId, + onAppLeave, + }, + services, + navActions + ); + } } }, [ isEmbeddableRendered, @@ -128,6 +169,8 @@ const TopNav = ({ embeddableId, stateTransfer, onAppLeave, + showActionsInGroup, + navActions, ]); const [indexPatterns, setIndexPatterns] = useState( vis.data.indexPattern ? [vis.data.indexPattern] : [] @@ -216,14 +259,15 @@ const TopNav = ({ savedQueryId={currentAppState.savedQuery} onSavedQueryIdChange={stateContainer.transitions.updateSavedQuery} indexPatterns={indexPatterns} - screenTitle={vis.title} + screenTitle={vis.title.length ?? '' ? vis.title : 'New visualization'} showAutoRefreshOnly={!showDatePicker()} showDatePicker={showDatePicker()} showFilterBar={showFilterBar} showQueryInput={showQueryInput} showSaveQuery={services.visualizeCapabilities.saveQuery} - showSearchBar + showSearchBar={TopNavMenuItemRenderType.IN_PORTAL} useDefaultBehaviors + groupActions={showActionsInGroup} /> ) : showFilterBar ? ( /** @@ -234,7 +278,7 @@ const TopNav = ({ appName={APP_NAME} setMenuMountPoint={setHeaderActionMenu} indexPatterns={indexPatterns} - showSearchBar + showSearchBar={TopNavMenuItemRenderType.IN_PORTAL} showSaveQuery={false} showDatePicker={false} showQueryInput={false} diff --git a/src/plugins/visualize/public/application/utils/constants.ts b/src/plugins/visualize/public/application/utils/constants.ts new file mode 100644 index 000000000000..0a62b13aff61 --- /dev/null +++ b/src/plugins/visualize/public/application/utils/constants.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export const VisualizeTopNavIds = { + SHARE: 'share', + INSPECT: 'inspect', + SAVE: 'save', + SAVEANDRETURN: 'saveAndReturn', + CANCEL: 'cancel', +}; diff --git a/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx b/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx index 562f96b872ba..cffd251b3eb4 100644 --- a/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx +++ b/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx @@ -50,6 +50,7 @@ import { import { VisualizeConstants } from '../visualize_constants'; import { getEditBreadcrumbs } from './breadcrumbs'; import { EmbeddableStateTransfer } from '../../../../embeddable/public'; +import { VisualizeTopNavIds } from './constants'; interface TopNavConfigParams { hasUnsavedChanges: boolean; @@ -66,7 +67,170 @@ interface TopNavConfigParams { onAppLeave: AppMountParameters['onAppLeave']; } -export const getTopNavConfig = ( +interface VisualizeNavActionMap { + [key: string]: (anchorElement?: any) => void; +} + +export const getLegacyTopNavConfig = ( + { + hasUnsavedChanges, + setHasUnsavedChanges, + openInspector, + originatingApp, + setOriginatingApp, + hasUnappliedChanges, + visInstance, + stateContainer, + visualizationIdFromUrl, + stateTransfer, + embeddableId, + onAppLeave, + }: TopNavConfigParams, + { + application, + chrome, + history, + share, + setActiveUrl, + toastNotifications, + visualizeCapabilities, + i18n: { Context: I18nContext }, + dashboard, + }: VisualizeServices, + navActions: VisualizeNavActionMap +) => { + const { vis, embeddableHandler } = visInstance; + const savedVis = 'savedVis' in visInstance ? visInstance.savedVis : undefined; + + const topNavMenu: TopNavMenuData[] = [ + { + id: 'inspector', + label: i18n.translate('visualize.topNavMenu.openInspectorButtonLabel', { + defaultMessage: 'inspect', + }), + description: i18n.translate('visualize.topNavMenu.openInspectorButtonAriaLabel', { + defaultMessage: 'Open Inspector for visualization', + }), + testId: 'openInspectorButton', + disableButton() { + return !embeddableHandler.hasInspector || !embeddableHandler.hasInspector(); + }, + run: navActions[VisualizeTopNavIds.INSPECT], + tooltip() { + if (!embeddableHandler.hasInspector || !embeddableHandler.hasInspector()) { + return i18n.translate('visualize.topNavMenu.openInspectorDisabledButtonTooltip', { + defaultMessage: `This visualization doesn't support any inspectors.`, + }); + } + }, + }, + { + id: 'share', + label: i18n.translate('visualize.topNavMenu.shareVisualizationButtonLabel', { + defaultMessage: 'share', + }), + description: i18n.translate('visualize.topNavMenu.shareVisualizationButtonAriaLabel', { + defaultMessage: 'Share Visualization', + }), + testId: 'shareTopNavButton', + run: navActions[VisualizeTopNavIds.SHARE], + // disable the Share button if no action specified + disableButton: !share || !!embeddableId, + }, + ...(originatingApp === 'dashboards' || originatingApp === 'canvas' + ? [ + { + id: 'cancel', + label: i18n.translate('visualize.topNavMenu.cancelButtonLabel', { + defaultMessage: 'Cancel', + }), + emphasize: false, + description: i18n.translate('visualize.topNavMenu.cancelButtonAriaLabel', { + defaultMessage: 'Return to the last app without saving changes', + }), + testId: 'visualizeCancelAndReturnButton', + tooltip() { + if (hasUnappliedChanges || hasUnsavedChanges) { + return i18n.translate('visualize.topNavMenu.cancelAndReturnButtonTooltip', { + defaultMessage: 'Discard your changes before finishing', + }); + } + }, + run: navActions[VisualizeTopNavIds.CANCEL], + }, + ] + : []), + ...(visualizeCapabilities.save && !embeddableId + ? [ + { + id: 'save', + iconType: savedVis?.id && originatingApp ? undefined : ('save' as const), + label: + savedVis?.id && originatingApp + ? i18n.translate('visualize.topNavMenu.saveVisualizationAsButtonLabel', { + defaultMessage: 'save as', + }) + : i18n.translate('visualize.topNavMenu.saveVisualizationButtonLabel', { + defaultMessage: 'save', + }), + emphasize: (savedVis && !savedVis.id) || !originatingApp, + description: i18n.translate('visualize.topNavMenu.saveVisualizationButtonAriaLabel', { + defaultMessage: 'Save Visualization', + }), + className: savedVis?.id && originatingApp ? 'saveAsButton' : '', + testId: 'visualizeSaveButton', + disableButton: hasUnappliedChanges, + tooltip() { + if (hasUnappliedChanges) { + return i18n.translate( + 'visualize.topNavMenu.saveVisualizationDisabledButtonTooltip', + { + defaultMessage: 'Apply or Discard your changes before saving', + } + ); + } + }, + run: navActions[VisualizeTopNavIds.SAVE], + }, + ] + : []), + ...(originatingApp && ((savedVis && savedVis.id) || embeddableId) + ? [ + { + id: 'saveAndReturn', + label: i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonLabel', { + defaultMessage: 'Save and return', + }), + emphasize: true, + iconType: 'checkInCircleFilled' as const, + description: i18n.translate( + 'visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel', + { + defaultMessage: 'Finish editing visualization and return to the last app', + } + ), + testId: 'visualizesaveAndReturnButton', + disableButton: hasUnappliedChanges, + tooltip() { + if (hasUnappliedChanges) { + return i18n.translate( + 'visualize.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip', + { + defaultMessage: 'Apply or Discard your changes before finishing', + } + ); + } + }, + run: navActions[VisualizeTopNavIds.SAVEANDRETURN], + }, + ] + : []), + ]; + + return topNavMenu; +}; + +export const getNavActions = ( { hasUnsavedChanges, setHasUnsavedChanges, @@ -95,9 +259,7 @@ export const getTopNavConfig = ( ) => { const { vis, embeddableHandler } = visInstance; const savedVis = 'savedVis' in visInstance ? visInstance.savedVis : undefined; - /** - * Called when the user clicks "Save" button. - */ + async function doSave(saveOptions: SavedObjectSaveOpts) { if (!savedVis) { return {}; @@ -194,218 +356,222 @@ export const getTopNavConfig = ( } }; - const topNavMenu: TopNavMenuData[] = [ + const navActions: VisualizeNavActionMap = {}; + + const saveAction = (anchorElement: HTMLElement) => { + const onSave = async ({ + newTitle, + newCopyOnSave, + isTitleDuplicateConfirmed, + onTitleDuplicate, + newDescription, + returnToOrigin, + }: OnSaveProps & { returnToOrigin: boolean }) => { + if (!savedVis) { + return; + } + const currentTitle = savedVis.title; + savedVis.title = newTitle; + embeddableHandler.updateInput({ title: newTitle }); + savedVis.copyOnSave = newCopyOnSave; + savedVis.description = newDescription; + const saveOptions = { + confirmOverwrite: false, + isTitleDuplicateConfirmed, + onTitleDuplicate, + returnToOrigin, + }; + const response = await doSave(saveOptions); + // If the save wasn't successful, put the original values back. + if (!response.id || response.error) { + savedVis.title = currentTitle; + } + return response; + }; + + const saveModal = ( + {}} + originatingApp={originatingApp} + /> + ); + const isSaveAsButton = anchorElement.classList.contains('saveAsButton'); + onAppLeave((actions) => { + return actions.default(); + }); + if ( + originatingApp === 'dashboards' && + dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables && + !isSaveAsButton + ) { + createVisReference(); + } else if (savedVis) { + showSaveModal(saveModal, I18nContext); + } + }; + navActions[VisualizeTopNavIds.SAVE] = saveAction; + + const saveAndReturnAction = async () => { + const saveOptions = { + confirmOverwrite: false, + returnToOrigin: true, + }; + onAppLeave((actions) => { + return actions.default(); + }); + if ( + originatingApp === 'dashboards' && + dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables && + !savedVis + ) { + return createVisReference(); + } + return doSave(saveOptions); + }; + navActions[VisualizeTopNavIds.SAVEANDRETURN] = saveAndReturnAction; + + const cancelAction = async () => { + return navigateToOriginatingApp(); + }; + navActions[VisualizeTopNavIds.CANCEL] = cancelAction; + + const shareAction = (anchorElement: HTMLElement) => { + if (share && !embeddableId) { + // TODO: support sharing in by-value mode + share.toggleShareContextMenu({ + anchorElement, + allowEmbed: true, + allowShortUrl: visualizeCapabilities.createShortUrl, + shareableUrl: unhashUrl(window.location.href), + objectId: savedVis?.id, + objectType: 'visualization', + sharingData: { + title: savedVis?.title, + }, + isDirty: hasUnappliedChanges || hasUnsavedChanges, + }); + } + }; + navActions[VisualizeTopNavIds.SHARE] = shareAction; + + navActions[VisualizeTopNavIds.INSPECT] = openInspector; + + return navActions; +}; + +export const getTopNavConfig = ( + { + hasUnsavedChanges, + setHasUnsavedChanges, + openInspector, + originatingApp, + setOriginatingApp, + hasUnappliedChanges, + visInstance, + stateContainer, + visualizationIdFromUrl, + stateTransfer, + embeddableId, + onAppLeave, + }: TopNavConfigParams, + { + application, + chrome, + history, + share, + setActiveUrl, + toastNotifications, + visualizeCapabilities, + i18n: { Context: I18nContext }, + dashboard, + }: VisualizeServices, + navActions: VisualizeNavActionMap +) => { + const { vis, embeddableHandler } = visInstance; + const savedVis = 'savedVis' in visInstance ? visInstance.savedVis : undefined; + + const topNavMenu = [ + ...(visualizeCapabilities.save && !embeddableId + ? [ + { + tooltip: i18n.translate('visualize.topNavMenu.saveVisualizationButtonLabel', { + defaultMessage: 'Save', + }), + ariaLabel: i18n.translate('visualize.topNavMenu.saveVisualizationAriaLabel', { + defaultMessage: 'Save visualization', + }), + testId: 'visualizeSaveButton', + run: navActions[VisualizeTopNavIds.SAVE], + iconType: 'save', + controlType: 'icon', + disableButton: hasUnappliedChanges, + }, + ] + : []), { - id: 'inspector', - label: i18n.translate('visualize.topNavMenu.openInspectorButtonLabel', { - defaultMessage: 'inspect', + tooltip: i18n.translate('visualize.topNavMenu.openInspectorTooltip', { + defaultMessage: 'Inspect', }), - description: i18n.translate('visualize.topNavMenu.openInspectorButtonAriaLabel', { - defaultMessage: 'Open Inspector for visualization', + ariaLabel: i18n.translate('visualize.topNavMenu.openInspectorButtonLabel', { + defaultMessage: 'Inspect', }), testId: 'openInspectorButton', - disableButton() { - return !embeddableHandler.hasInspector || !embeddableHandler.hasInspector(); - }, - run: openInspector, - tooltip() { - if (!embeddableHandler.hasInspector || !embeddableHandler.hasInspector()) { - return i18n.translate('visualize.topNavMenu.openInspectorDisabledButtonTooltip', { - defaultMessage: `This visualization doesn't support any inspectors.`, - }); - } - }, + run: navActions[VisualizeTopNavIds.INSPECT], + iconType: 'inspect', + controlType: 'icon', + disabled: !embeddableHandler.hasInspector || !embeddableHandler.hasInspector(), }, { - id: 'share', - label: i18n.translate('visualize.topNavMenu.shareVisualizationButtonLabel', { - defaultMessage: 'share', + tooltip: i18n.translate('visualize.topNavMenu.shareVisualizationButtonLabel', { + defaultMessage: 'Share', }), - description: i18n.translate('visualize.topNavMenu.shareVisualizationButtonAriaLabel', { + ariaLabel: i18n.translate('visualize.topNavMenu.shareVisualizationButtonAriaLabel', { defaultMessage: 'Share Visualization', }), testId: 'shareTopNavButton', - run: (anchorElement) => { - if (share && !embeddableId) { - // TODO: support sharing in by-value mode - share.toggleShareContextMenu({ - anchorElement, - allowEmbed: true, - allowShortUrl: visualizeCapabilities.createShortUrl, - shareableUrl: unhashUrl(window.location.href), - objectId: savedVis?.id, - objectType: 'visualization', - sharingData: { - title: savedVis?.title, - }, - isDirty: hasUnappliedChanges || hasUnsavedChanges, - }); - } - }, - // disable the Share button if no action specified - disableButton: !share || !!embeddableId, + run: navActions[VisualizeTopNavIds.SHARE], + iconType: 'share', + controlType: 'icon', + disabled: !share || !!embeddableId, }, ...(originatingApp === 'dashboards' || originatingApp === 'canvas' ? [ { - id: 'cancel', - label: i18n.translate('visualize.topNavMenu.cancelButtonLabel', { - defaultMessage: 'Cancel', + tooltip: i18n.translate('visualize.topNavMenu.cancelAndReturnButtonTooltip', { + defaultMessage: 'Discard your changes before finishing', }), - emphasize: false, - description: i18n.translate('visualize.topNavMenu.cancelButtonAriaLabel', { + ariaLabel: i18n.translate('visualize.topNavMenu.cancelButtonAriaLabel', { defaultMessage: 'Return to the last app without saving changes', }), testId: 'visualizeCancelAndReturnButton', - tooltip() { - if (hasUnappliedChanges || hasUnsavedChanges) { - return i18n.translate('visualize.topNavMenu.cancelAndReturnButtonTooltip', { - defaultMessage: 'Discard your changes before finishing', - }); - } - }, - run: async () => { - return navigateToOriginatingApp(); - }, - }, - ] - : []), - ...(visualizeCapabilities.save && !embeddableId - ? [ - { - id: 'save', - iconType: savedVis?.id && originatingApp ? undefined : ('save' as const), - label: - savedVis?.id && originatingApp - ? i18n.translate('visualize.topNavMenu.saveVisualizationAsButtonLabel', { - defaultMessage: 'save as', - }) - : i18n.translate('visualize.topNavMenu.saveVisualizationButtonLabel', { - defaultMessage: 'save', - }), - emphasize: (savedVis && !savedVis.id) || !originatingApp, - description: i18n.translate('visualize.topNavMenu.saveVisualizationButtonAriaLabel', { - defaultMessage: 'Save Visualization', - }), - className: savedVis?.id && originatingApp ? 'saveAsButton' : '', - testId: 'visualizeSaveButton', - disableButton: hasUnappliedChanges, - tooltip() { - if (hasUnappliedChanges) { - return i18n.translate( - 'visualize.topNavMenu.saveVisualizationDisabledButtonTooltip', - { - defaultMessage: 'Apply or Discard your changes before saving', - } - ); - } - }, - run: (anchorElement: HTMLElement) => { - const onSave = async ({ - newTitle, - newCopyOnSave, - isTitleDuplicateConfirmed, - onTitleDuplicate, - newDescription, - returnToOrigin, - }: OnSaveProps & { returnToOrigin: boolean }) => { - if (!savedVis) { - return; - } - const currentTitle = savedVis.title; - savedVis.title = newTitle; - embeddableHandler.updateInput({ title: newTitle }); - savedVis.copyOnSave = newCopyOnSave; - savedVis.description = newDescription; - const saveOptions = { - confirmOverwrite: false, - isTitleDuplicateConfirmed, - onTitleDuplicate, - returnToOrigin, - }; - const response = await doSave(saveOptions); - // If the save wasn't successful, put the original values back. - if (!response.id || response.error) { - savedVis.title = currentTitle; - } - return response; - }; - - const saveModal = ( - {}} - originatingApp={originatingApp} - /> - ); - const isSaveAsButton = anchorElement.classList.contains('saveAsButton'); - onAppLeave((actions) => { - return actions.default(); - }); - if ( - originatingApp === 'dashboards' && - dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables && - !isSaveAsButton - ) { - createVisReference(); - } else if (savedVis) { - showSaveModal(saveModal, I18nContext); - } - }, + run: navActions[VisualizeTopNavIds.CANCEL], + iconType: 'cross', + controlType: 'icon', }, ] : []), ...(originatingApp && ((savedVis && savedVis.id) || embeddableId) ? [ { - id: 'saveAndReturn', - label: i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonLabel', { + tooltip: i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonLabel', { defaultMessage: 'Save and return', }), - emphasize: true, - iconType: 'checkInCircleFilled' as const, - description: i18n.translate( - 'visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel', - { - defaultMessage: 'Finish editing visualization and return to the last app', - } - ), + ariaLabel: hasUnappliedChanges + ? i18n.translate('visualize.topNavMenu.saveAndReturnVisualizationButtonAriaLabel', { + defaultMessage: 'Finish editing visualization and return to the last app', + }) + : '', testId: 'visualizesaveAndReturnButton', - disableButton: hasUnappliedChanges, - tooltip() { - if (hasUnappliedChanges) { - return i18n.translate( - 'visualize.topNavMenu.saveAndReturnVisualizationDisabledButtonTooltip', - { - defaultMessage: 'Apply or Discard your changes before finishing', - } - ); - } - }, - run: async () => { - const saveOptions = { - confirmOverwrite: false, - returnToOrigin: true, - }; - onAppLeave((actions) => { - return actions.default(); - }); - if ( - originatingApp === 'dashboards' && - dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables && - !savedVis - ) { - return createVisReference(); - } - return doSave(saveOptions); - }, + run: navActions[VisualizeTopNavIds.SAVEANDRETURN], + iconType: 'checkInCircleFilled', + controlType: 'icon', }, ] : []), ]; - - return topNavMenu; + return topNavMenu as TopNavMenuData[]; }; From db59890c05e0aba66d87d23907ee9b0da18e2b36 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:37:37 -0700 Subject: [PATCH 220/276] [Look & Feel] Appearance Popover Button Change (#7777) (#7782) * dropped the primary button for apply * Changeset file for PR #7777 created/updated --------- (cherry picked from commit b4ae264f8500f29dfb4bedcbc13d04fd2a2661d5) Signed-off-by: Shey Gao Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: Shey Gao Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7777.yml | 2 ++ src/plugins/advanced_settings/public/header_user_theme_menu.tsx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/7777.yml diff --git a/changelogs/fragments/7777.yml b/changelogs/fragments/7777.yml new file mode 100644 index 000000000000..465c80e318c3 --- /dev/null +++ b/changelogs/fragments/7777.yml @@ -0,0 +1,2 @@ +refactor: +- [Look & Feel] Appearance Popover Button Change ([#7777](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7777)) \ No newline at end of file diff --git a/src/plugins/advanced_settings/public/header_user_theme_menu.tsx b/src/plugins/advanced_settings/public/header_user_theme_menu.tsx index b1d6f09dafff..86a78cbcc2d2 100644 --- a/src/plugins/advanced_settings/public/header_user_theme_menu.tsx +++ b/src/plugins/advanced_settings/public/header_user_theme_menu.tsx @@ -178,7 +178,7 @@ export const HeaderUserThemeMenu = () => { {/* TODO: disable submit until changes */} - + Apply From 9c01cff6f42ec305d85d19fd7c85c9f8545d91e1 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:58:57 -0700 Subject: [PATCH 221/276] [Page Header]Make saved queries a context menu item in filter options instead of a button (#7788) (#7790) (cherry picked from commit 9d692ef31e133d32a276b9fd2ee76d135014986b) Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../ui/filter_bar/filter_options.test.tsx | 6 +- .../public/ui/filter_bar/filter_options.tsx | 62 ++++++++----------- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/plugins/data/public/ui/filter_bar/filter_options.test.tsx b/src/plugins/data/public/ui/filter_bar/filter_options.test.tsx index f48e744528e9..163e35060d68 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_options.test.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_options.test.tsx @@ -92,14 +92,12 @@ describe('Filter options menu', () => { expect(wrapper.find('[data-test-subj="add-filter-panel"]').exists()).toBeTruthy(); }); - it("render filter options with 'Save Query' button", () => { + it("render saved query panel with 'saved queries' button", () => { const wrapper = mountWithIntl(); const button = wrapper.find('[data-test-subj="showFilterActions"]').at(0); button.simulate('click'); wrapper.update(); - const saveQueryButton = wrapper - .find('[data-test-subj="saved-query-management-save-button"]') - .at(0); + const saveQueryButton = wrapper.find('[data-test-subj="savedQueries"]').at(0); expect(saveQueryButton.exists()).toBeTruthy(); saveQueryButton.simulate('click'); expect(wrapper.find('[data-test-subj="save-query-panel"]').exists()).toBeTruthy(); diff --git a/src/plugins/data/public/ui/filter_bar/filter_options.tsx b/src/plugins/data/public/ui/filter_bar/filter_options.tsx index 82c2be66875d..3edd47e3fddc 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_options.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_options.tsx @@ -32,14 +32,13 @@ import { EuiContextMenu, EuiPopover, EuiToolTip, - EuiButton, - EuiPopoverFooter, - EuiFlexGroup, EuiFlexItem, EuiSmallButtonEmpty, EuiIcon, EuiResizeObserver, + EuiContextMenuPanelItemDescriptor, EuiContextMenuPanel, + EuiContextMenuPanelDescriptor, } from '@elastic/eui'; import { stringify } from '@osd/std'; import { InjectedIntl, injectI18n } from '@osd/i18n/react'; @@ -83,7 +82,6 @@ const FilterOptionsUI = (props: Props) => { const [isPopoverOpen, setIsPopoverOpen] = React.useState(false); const [renderedComponent, setRenderedComponent] = React.useState('menu'); const [filterWidth, setFilterWidth] = React.useState(maxFilterWidth); - const [showSaveQueryButton, setShowSaveQueryButton] = React.useState(true); const opensearchDashboards = useOpenSearchDashboards(); const uiSettings = opensearchDashboards.services.uiSettings; const isPinned = uiSettings!.get(UI_SETTINGS.FILTERS_PINNED_BY_DEFAULT); @@ -94,7 +92,6 @@ const FilterOptionsUI = (props: Props) => { const togglePopover = () => { setRenderedComponent('menu'); - setShowSaveQueryButton(true); setIsPopoverOpen((prevState) => !prevState); }; @@ -152,7 +149,7 @@ const FilterOptionsUI = (props: Props) => { setFilterWidth(dimensions.width); } - const addFilterPanelItem = { + const addFilterPanelItem: EuiContextMenuPanelItemDescriptor = { name: props.intl.formatMessage({ id: 'data.filter.options.addFiltersButtonLabel', defaultMessage: 'Add filters', @@ -160,15 +157,32 @@ const FilterOptionsUI = (props: Props) => { icon: 'plusInCircle', onClick: () => { setRenderedComponent('addFilter'); - setShowSaveQueryButton(false); }, 'data-test-subj': 'addFilters', disabled: false, }; + const savedQueriesPanelItem: EuiContextMenuPanelItemDescriptor = { + name: props.intl.formatMessage({ + id: 'data.filter.options.savedQueriesButtonLabel', + defaultMessage: 'Saved queries', + }), + icon: 'folderOpen', + onClick: () => { + setRenderedComponent('saveQuery'); + }, + 'data-test-subj': 'savedQueries', + disabled: false, + }; + + const menuOptionsSeparator: EuiContextMenuPanelItemDescriptor = { + isSeparator: true, + key: 'sep', + }; + const disableMenuOption = props.filters.length === 0 && useNewHeader; - const panelTree = [ + const panelTree: EuiContextMenuPanelDescriptor[] = [ { id: 0, title: 'Filters', @@ -339,7 +353,10 @@ const FilterOptionsUI = (props: Props) => { }; if (useNewHeader) { - panelTree[0].items.unshift(addFilterPanelItem); + panelTree[0].items?.unshift(addFilterPanelItem); + panelTree[0].items?.push(menuOptionsSeparator); + panelTree[0].items?.push(savedQueriesPanelItem); + panelTree[0].title = ''; } const label = i18n.translate('data.search.searchBar.savedQueryPopoverButtonText', { @@ -395,33 +412,6 @@ const FilterOptionsUI = (props: Props) => { repositionOnScroll > {useNewHeader ? renderComponent() : props.useSaveQueryMenu ? saveQueryPanel : menuPanel} - {useNewHeader && showSaveQueryButton && ( - - - - { - setRenderedComponent('saveQuery'); - setShowSaveQueryButton(false); - }} - > - {i18n.translate('data.search.searchBar.savedQueryPopoverSaveButtonText', { - defaultMessage: 'Save query', - })} - - - - - )} ); }; From f2faa0a3fa603b610da70309177b9471a79bfdab Mon Sep 17 00:00:00 2001 From: Anan Zhuang Date: Wed, 21 Aug 2024 20:35:47 -0700 Subject: [PATCH 222/276] [2.x manual backport]Change the locale dynamically by adding &i18n-locale to URL (#7686) (#7781) Backport PR: https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7686 * Change the locale dynamically by adding &i18n-locale to URL The main issue was the inability to dynamically change the locale in OpenSearch Dashboards. Currently we need to update config file and i18nrc.json. This PR allows users to switch to a different locale (e.g., from English to Chinese) by appending or modifying the 'i18n-locale' parameter in the URL. * getAndUpdateLocaleInUrl: If a non-default locale is found, this function reconstructs the URL with the locale parameter in the correct position. * updated the ScopedHistory class, allowing it to detect locale changes and trigger reloads as necessary. * modify the i18nMixin, which sets up the i18n system during server startup, to register all available translation files during server startup, not just the current locale. * update the uiRenderMixin to accept requests for any registered locale and dynamically load and cache translations for requested locales. --------- Signed-off-by: Anan Zhuang Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7686.yml | 2 + packages/osd-i18n/src/core/i18n.test.ts | 34 +++- packages/osd-i18n/src/core/i18n.ts | 9 +- .../public/application/scoped_history.test.ts | 60 ++++++ src/core/public/application/scoped_history.ts | 11 ++ src/core/public/locale_helper.test.ts | 50 +++++ src/core/public/locale_helper.ts | 68 +++++++ src/core/public/osd_bootstrap.test.mocks.ts | 28 +-- src/core/public/osd_bootstrap.test.ts | 67 ++++++- src/core/public/osd_bootstrap.ts | 49 +++++ src/dev/jest/config.js | 1 - src/legacy/server/i18n/index.ts | 11 +- src/legacy/ui/ui_render/ui_render_mixin.js | 67 +++++-- .../ui/ui_render/ui_render_mixin.test.js | 175 ++++++++++++++++++ 14 files changed, 592 insertions(+), 40 deletions(-) create mode 100644 changelogs/fragments/7686.yml create mode 100644 src/core/public/locale_helper.test.ts create mode 100644 src/core/public/locale_helper.ts create mode 100644 src/legacy/ui/ui_render/ui_render_mixin.test.js diff --git a/changelogs/fragments/7686.yml b/changelogs/fragments/7686.yml new file mode 100644 index 000000000000..f446ed68764c --- /dev/null +++ b/changelogs/fragments/7686.yml @@ -0,0 +1,2 @@ +feat: +- Change the locale dynamically by adding &i18n-locale to URL ([#7686](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7686)) \ No newline at end of file diff --git a/packages/osd-i18n/src/core/i18n.test.ts b/packages/osd-i18n/src/core/i18n.test.ts index 0ee114c78c95..ebfd546f8561 100644 --- a/packages/osd-i18n/src/core/i18n.test.ts +++ b/packages/osd-i18n/src/core/i18n.test.ts @@ -899,8 +899,17 @@ describe('I18n engine', () => { describe('load', () => { let mockFetch: jest.SpyInstance; + let originalWindow: any; + beforeEach(() => { mockFetch = jest.spyOn(global as any, 'fetch').mockImplementation(); + originalWindow = global.window; + global.window = { ...originalWindow }; + }); + + afterEach(() => { + global.window = originalWindow; + delete (window as any).__i18nWarning; // Clear the warning after each test }); test('fails if server returns >= 300 status code', async () => { @@ -928,7 +937,7 @@ describe('I18n engine', () => { mockFetch.mockResolvedValue({ status: 200, - json: jest.fn().mockResolvedValue(translations), + json: jest.fn().mockResolvedValue({ translations }), }); await expect(i18n.load('some-url')).resolves.toBeUndefined(); @@ -938,5 +947,28 @@ describe('I18n engine', () => { expect(i18n.getTranslation()).toEqual(translations); }); + + test('sets warning on window when present in response', async () => { + const warning = { title: 'Warning', text: 'This is a warning' }; + mockFetch.mockResolvedValue({ + status: 200, + json: jest.fn().mockResolvedValue({ translations: { locale: 'en' }, warning }), + }); + + await i18n.load('some-url'); + + expect((window as any).__i18nWarning).toEqual(warning); + }); + + test('does not set warning on window when not present in response', async () => { + mockFetch.mockResolvedValue({ + status: 200, + json: jest.fn().mockResolvedValue({ translations: { locale: 'en' } }), + }); + + await i18n.load('some-url'); + + expect((window as any).__i18nWarning).toBeUndefined(); + }); }); }); diff --git a/packages/osd-i18n/src/core/i18n.ts b/packages/osd-i18n/src/core/i18n.ts index 3268fae5079f..65da4931ef13 100644 --- a/packages/osd-i18n/src/core/i18n.ts +++ b/packages/osd-i18n/src/core/i18n.ts @@ -261,5 +261,12 @@ export async function load(translationsUrl: string) { throw new Error(`Translations request failed with status code: ${response.status}`); } - init(await response.json()); + const data = await response.json(); + + if (data.warning) { + // Store the warning to be displayed after core system setup + (window as any).__i18nWarning = data.warning; + } + + init(data.translations); } diff --git a/src/core/public/application/scoped_history.test.ts b/src/core/public/application/scoped_history.test.ts index 067c33256bd1..6575a6aa1ab1 100644 --- a/src/core/public/application/scoped_history.test.ts +++ b/src/core/public/application/scoped_history.test.ts @@ -30,8 +30,23 @@ import { ScopedHistory } from './scoped_history'; import { createMemoryHistory } from 'history'; +import { getLocaleInUrl } from '../locale_helper'; +import { i18n } from '@osd/i18n'; + +jest.mock('../locale_helper', () => ({ + getLocaleInUrl: jest.fn(), +})); + +jest.mock('@osd/i18n', () => ({ + i18n: { + getLocale: jest.fn(), + }, +})); describe('ScopedHistory', () => { + beforeEach(() => { + (getLocaleInUrl as jest.Mock).mockReturnValue('en'); + }); describe('construction', () => { it('succeeds if current location matches basePath', () => { const gh = createMemoryHistory(); @@ -358,4 +373,49 @@ describe('ScopedHistory', () => { expect(gh.length).toBe(4); }); }); + + describe('locale handling', () => { + let originalLocation: Location; + + beforeEach(() => { + originalLocation = window.location; + delete (window as any).location; + window.location = { href: 'http://localhost/app/wow', reload: jest.fn() } as any; + (i18n.getLocale as jest.Mock).mockReturnValue('en'); + }); + + afterEach(() => { + window.location = originalLocation; + jest.resetAllMocks(); + }); + + it('reloads the page when locale changes', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + const h = new ScopedHistory(gh, '/app/wow'); + // Use the 'h' variable to trigger the listener + h.push('/new-page'); + + // Mock getLocaleInUrl to return a different locale + (getLocaleInUrl as jest.Mock).mockReturnValue('fr'); + + // Simulate navigation + gh.push('/app/wow/new-page'); + + expect(window.location.reload).toHaveBeenCalled(); + }); + + it('does not reload the page when locale changes', () => { + const gh = createMemoryHistory(); + gh.push('/app/wow'); + + // Mock getLocaleInUrl to return a different locale + (getLocaleInUrl as jest.Mock).mockReturnValue('en'); + + // Simulate navigation + gh.push('/app/wow/new-page'); + + expect(window.location.reload).not.toHaveBeenCalled(); + }); + }); }); diff --git a/src/core/public/application/scoped_history.ts b/src/core/public/application/scoped_history.ts index 487093be191f..74e4bb068d3e 100644 --- a/src/core/public/application/scoped_history.ts +++ b/src/core/public/application/scoped_history.ts @@ -39,6 +39,8 @@ import { Href, Action, } from 'history'; +import { i18n } from '@osd/i18n'; +import { getLocaleInUrl } from '../locale_helper'; /** * A wrapper around a `History` instance that is scoped to a particular base path of the history stack. Behaves @@ -307,6 +309,7 @@ export class ScopedHistory * state. Also forwards events to child listeners with the base path stripped from the location. */ private setupHistoryListener() { + const currentLocale = i18n.getLocale() || 'en'; const unlisten = this.parentHistory.listen((location, action) => { // If the user navigates outside the scope of this basePath, tear it down. if (!location.pathname.startsWith(this.basePath)) { @@ -315,6 +318,14 @@ export class ScopedHistory return; } + const localeValue = getLocaleInUrl(window.location.href); + + if (localeValue !== currentLocale) { + // Force a full page reload + window.location.reload(); + return; + } + /** * Track location keys using the same algorithm the browser uses internally. * - On PUSH, remove all items that came after the current location and append the new location. diff --git a/src/core/public/locale_helper.test.ts b/src/core/public/locale_helper.test.ts new file mode 100644 index 000000000000..238dbced3892 --- /dev/null +++ b/src/core/public/locale_helper.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { getLocaleInUrl } from './locale_helper'; + +describe('getLocaleInUrl', () => { + beforeEach(() => { + // Clear any warnings before each test + delete (window as any).__localeWarning; + }); + + it('should return the locale from a valid query string', () => { + const url = 'http://localhost:5603/app/home?locale=en-US'; + expect(getLocaleInUrl(url)).toBe('en-US'); + }); + + it('should return the locale from a valid hash query string', () => { + const url = 'http://localhost:5603/app/home#/?locale=fr-FR'; + expect(getLocaleInUrl(url)).toBe('fr-FR'); + }); + + it('should return en for a URL without locale', () => { + const url = 'http://localhost:5603/app/home'; + expect(getLocaleInUrl(url)).toBe('en'); + }); + + it('should return en and set a warning for an invalid locale format in hash', () => { + const url = 'http://localhost:5603/app/home#/&locale=de-DE'; + expect(getLocaleInUrl(url)).toBe('en'); + expect((window as any).__localeWarning).toBeDefined(); + expect((window as any).__localeWarning.title).toBe('Invalid URL Format'); + }); + + it('should return en for an empty locale value', () => { + const url = 'http://localhost:5603/app/home?locale='; + expect(getLocaleInUrl(url)).toBe('en'); + }); + + it('should handle URLs with other query parameters', () => { + const url = 'http://localhost:5603/app/home?param1=value1&locale=ja-JP¶m2=value2'; + expect(getLocaleInUrl(url)).toBe('ja-JP'); + }); + + it('should handle URLs with other hash parameters', () => { + const url = 'http://localhost:5603/app/home#/route?param1=value1&locale=zh-CN¶m2=value2'; + expect(getLocaleInUrl(url)).toBe('zh-CN'); + }); +}); diff --git a/src/core/public/locale_helper.ts b/src/core/public/locale_helper.ts new file mode 100644 index 000000000000..38a734a523b1 --- /dev/null +++ b/src/core/public/locale_helper.ts @@ -0,0 +1,68 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Extracts the locale value from a given URL. + * + * This function looks for the 'locale' parameter in either the main query string + * or in the hash part of the URL. It supports two valid formats: + * 1. As a regular query parameter: "?locale=xx-XX" + * 2. In the hash with a proper query string: "#/?locale=xx-XX" + * + * If an invalid format is detected, it sets a warning message on the window object. + * + * @param url - The URL to extract the locale from + * @returns The locale value if found and valid, or null otherwise + */ +export function getLocaleInUrl(url: string): string | null { + let urlObject: URL; + // Attempt to parse the URL, return null if invalid + try { + urlObject = new URL(url, window.location.origin); + } catch (error) { + setInvalidUrlWarning(); + return null; + } + + let localeValue: string | null = null; + + // Check for locale in the main query string + if (urlObject.searchParams.has('locale')) { + localeValue = urlObject.searchParams.get('locale'); + } + // Check for locale in the hash, but only if it's in proper query string format + else if (urlObject.hash.includes('?')) { + const hashParams = new URLSearchParams(urlObject.hash.split('?')[1]); + if (hashParams.has('locale')) { + localeValue = hashParams.get('locale'); + } + } + + // Check for non standard query format: + if (localeValue === null && url.includes('&locale=')) { + setInvalidUrlWithLocaleWarning(); + return 'en'; + } + + // Return the locale value if found, or 'en' if not found + return localeValue && localeValue.trim() !== '' ? localeValue : 'en'; +} + +function setInvalidUrlWarning(): void { + (window as any).__localeWarning = { + title: 'Invalid URL Format', + text: 'The provided URL is not in a valid format.', + }; +} + +function setInvalidUrlWithLocaleWarning(): void { + (window as any).__localeWarning = { + title: 'Invalid URL Format', + text: + 'The locale parameter is not in a valid URL format. ' + + 'Use either "?locale=xx-XX" in the main URL or "#/?locale=xx-XX" in the hash. ' + + 'For example: "yourapp.com/page?locale=en-US" or "yourapp.com/page#/?locale=en-US".', + }; +} diff --git a/src/core/public/osd_bootstrap.test.mocks.ts b/src/core/public/osd_bootstrap.test.mocks.ts index 77b47e8b895b..87a6ab499731 100644 --- a/src/core/public/osd_bootstrap.test.mocks.ts +++ b/src/core/public/osd_bootstrap.test.mocks.ts @@ -31,18 +31,6 @@ import { applicationServiceMock } from './application/application_service.mock'; import { fatalErrorsServiceMock } from './fatal_errors/fatal_errors_service.mock'; export const fatalErrorMock = fatalErrorsServiceMock.createSetupContract(); -export const coreSystemMock = { - setup: jest.fn().mockResolvedValue({ - fatalErrors: fatalErrorMock, - }), - start: jest.fn().mockResolvedValue({ - application: applicationServiceMock.createInternalStartContract(), - }), -}; -jest.doMock('./core_system', () => ({ - CoreSystem: jest.fn().mockImplementation(() => coreSystemMock), -})); - export const apmSystem = { setup: jest.fn().mockResolvedValue(undefined), start: jest.fn().mockResolvedValue(undefined), @@ -53,9 +41,25 @@ jest.doMock('./apm_system', () => ({ })); export const i18nLoad = jest.fn().mockResolvedValue(undefined); +export const i18nSetLocale = jest.fn(); jest.doMock('@osd/i18n', () => ({ i18n: { ...jest.requireActual('@osd/i18n').i18n, load: i18nLoad, + setLocale: i18nSetLocale, }, })); + +export const coreSystemMock = { + setup: jest.fn().mockResolvedValue({ + fatalErrors: fatalErrorMock, + }), + start: jest.fn().mockResolvedValue({ + application: applicationServiceMock.createInternalStartContract(), + }), +}; +jest.doMock('./core_system', () => ({ + CoreSystem: jest.fn().mockImplementation(() => coreSystemMock), +})); + +export const consoleWarnMock = jest.spyOn(console, 'warn').mockImplementation(() => {}); diff --git a/src/core/public/osd_bootstrap.test.ts b/src/core/public/osd_bootstrap.test.ts index 806841287bee..7630b4441ab6 100644 --- a/src/core/public/osd_bootstrap.test.ts +++ b/src/core/public/osd_bootstrap.test.ts @@ -28,22 +28,46 @@ * under the License. */ -import { apmSystem, fatalErrorMock, i18nLoad } from './osd_bootstrap.test.mocks'; +import { + apmSystem, + fatalErrorMock, + i18nLoad, + i18nSetLocale, + consoleWarnMock, +} from './osd_bootstrap.test.mocks'; import { __osdBootstrap__ } from './'; +import { getLocaleInUrl } from './locale_helper'; + +jest.mock('./locale_helper', () => ({ + getLocaleInUrl: jest.fn(), +})); describe('osd_bootstrap', () => { + let originalWindowLocation: Location; + beforeAll(() => { const metadata = { - i18n: { translationsUrl: 'http://localhost' }, + branding: { darkMode: 'true' }, + i18n: { translationsUrl: 'http://localhost/translations/en.json' }, vars: { apmConfig: null }, }; // eslint-disable-next-line no-unsanitized/property - document.body.innerHTML = ` -`; + document.body.innerHTML = ` `; + + originalWindowLocation = window.location; + delete (window as any).location; + window.location = { ...originalWindowLocation, href: 'http://localhost' }; }); beforeEach(() => { jest.clearAllMocks(); + (getLocaleInUrl as jest.Mock).mockReturnValue(null); + }); + + afterAll(() => { + window.location = originalWindowLocation; }); it('does not report a fatal error if apm load fails', async () => { @@ -63,4 +87,39 @@ describe('osd_bootstrap', () => { expect(fatalErrorMock.add).toHaveBeenCalledTimes(1); }); + + it('sets locale from URL if present', async () => { + (getLocaleInUrl as jest.Mock).mockReturnValue('fr'); + window.location.href = 'http://localhost/?locale=fr'; + + await __osdBootstrap__(); + + expect(i18nSetLocale).toHaveBeenCalledWith('fr'); + expect(i18nLoad).toHaveBeenCalledWith('http://localhost/translations/fr.json'); + }); + + it('sets default locale if not present in URL', async () => { + await __osdBootstrap__(); + + expect(i18nSetLocale).toHaveBeenCalledWith('en'); + expect(i18nLoad).toHaveBeenCalledWith('http://localhost/translations/en.json'); + }); + + it('displays locale warning if set', async () => { + (window as any).__localeWarning = { title: 'Locale Warning', text: 'Invalid locale' }; + + await __osdBootstrap__(); + + expect(consoleWarnMock).toHaveBeenCalledWith('Locale Warning: Invalid locale'); + expect((window as any).__localeWarning).toBeUndefined(); + }); + + it('displays i18n warning if set', async () => { + (window as any).__i18nWarning = { title: 'i18n Warning', text: 'Translation issue' }; + + await __osdBootstrap__(); + + expect(consoleWarnMock).toHaveBeenCalledWith('i18n Warning: Translation issue'); + expect((window as any).__i18nWarning).toBeUndefined(); + }); }); diff --git a/src/core/public/osd_bootstrap.ts b/src/core/public/osd_bootstrap.ts index f5571292b83a..5190fdc37e21 100644 --- a/src/core/public/osd_bootstrap.ts +++ b/src/core/public/osd_bootstrap.ts @@ -31,6 +31,7 @@ import { i18n } from '@osd/i18n'; import { CoreSystem } from './core_system'; import { ApmSystem } from './apm_system'; +import { getLocaleInUrl } from './locale_helper'; /** @internal */ export async function __osdBootstrap__() { @@ -38,6 +39,38 @@ export async function __osdBootstrap__() { document.querySelector('osd-injected-metadata')!.getAttribute('data')! ); + // Extract the locale from the URL if present + const currentLocale = i18n.getLocale(); + const urlLocale = getLocaleInUrl(window.location.href); + + if (urlLocale && urlLocale !== currentLocale) { + // If a locale is specified in the URL, update the i18n settings + // This enables dynamic language switching + // Note: This works in conjunction with server-side changes: + // 1. The server registers all available translation files at startup + // 2. A server route handles requests for specific locale translations + + // Set the locale in the i18n core + // This will affect all subsequent i18n.translate() calls + i18n.setLocale(urlLocale); + + // Modify the translationsUrl to include the new locale + // This ensures that the correct translation file is requested from the server + // The replace function changes the locale in the URL, e.g., + // from '/translations/en.json' to '/translations/zh-CN.json' + injectedMetadata.i18n.translationsUrl = injectedMetadata.i18n.translationsUrl.replace( + /\/([^/]+)\.json$/, + `/${urlLocale}.json` + ); + } else if (!urlLocale) { + i18n.setLocale('en'); + } + + const globals: any = typeof window === 'undefined' ? {} : window; + const themeTag: string = globals.__osdThemeTag__ || ''; + + injectedMetadata.branding.darkMode = themeTag.endsWith('dark'); + let i18nError: Error | undefined; const apmSystem = new ApmSystem(injectedMetadata.vars.apmConfig, injectedMetadata.basePath); @@ -62,4 +95,20 @@ export async function __osdBootstrap__() { const start = await coreSystem.start(); await apmSystem.start(start); + + // Display the i18n warning if it exists + if ((window as any).__i18nWarning) { + const warning = (window as any).__i18nWarning; + // eslint-disable-next-line no-console + console.warn(`${warning.title}: ${warning.text}`); + delete (window as any).__i18nWarning; + } + + // Display the locale warning if it exists + if ((window as any).__localeWarning) { + const warning = (window as any).__localeWarning; + // eslint-disable-next-line no-console + console.warn(`${warning.title}: ${warning.text}`); + delete (window as any).__localeWarning; + } } diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index c9239710b398..fb630556c91b 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -122,7 +122,6 @@ const ciGroups = process.argv.reduce((acc, arg) => { return acc; }, []); -console.log('ciGroups', ciGroups); if (ciGroups.length > 0) { console.log(`Requested group${ciGroups.length === 1 ? '' : 's'}: ${ciGroups.join(', ')}`); ciGroups.forEach((id) => { diff --git a/src/legacy/server/i18n/index.ts b/src/legacy/server/i18n/index.ts index e30f9bf7d72b..8a571144cdf5 100644 --- a/src/legacy/server/i18n/index.ts +++ b/src/legacy/server/i18n/index.ts @@ -62,10 +62,11 @@ export async function i18nMixin( }), ]); - const currentTranslationPaths = ([] as string[]) - .concat(...translationPaths) - .filter((translationPath) => basename(translationPath, '.json') === locale); - i18nLoader.registerTranslationFiles(currentTranslationPaths); + // Flatten the array of arrays + const allTranslationPaths = ([] as string[]).concat(...translationPaths); + + // Register all translation files, not just the ones for the current locale + i18nLoader.registerTranslationFiles(allTranslationPaths); const translations = await i18nLoader.getTranslationsByLocale(locale); i18n.init( @@ -75,7 +76,7 @@ export async function i18nMixin( }) ); - const getTranslationsFilePaths = () => currentTranslationPaths; + const getTranslationsFilePaths = () => allTranslationPaths; server.decorate('server', 'getTranslationsFilePaths', getTranslationsFilePaths); diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js index 24837ba4a085..f950f708e2c3 100644 --- a/src/legacy/ui/ui_render/ui_render_mixin.js +++ b/src/legacy/ui/ui_render/ui_render_mixin.js @@ -30,7 +30,7 @@ import { createHash } from 'crypto'; import Boom from '@hapi/boom'; -import { i18n } from '@osd/i18n'; +import { i18n, i18nLoader } from '@osd/i18n'; import * as UiSharedDeps from '@osd/ui-shared-deps'; import { OpenSearchDashboardsRequest } from '../../../core/server'; import { AppBootstrap } from './bootstrap'; @@ -49,32 +49,67 @@ import { getApmConfig } from '../apm'; */ export function uiRenderMixin(osdServer, server, config) { const translationsCache = { translations: null, hash: null }; + const defaultLocale = i18n.getLocale() || 'en'; // Fallback to 'en' if no default locale is set + + // Route handler for serving translation files. + // This handler supports two scenarios: + // 1. Serving translations for the default locale + // 2. Serving translations for other registered locales server.route({ path: '/translations/{locale}.json', method: 'GET', config: { auth: false }, - handler(request, h) { - // OpenSearch Dashboards server loads translations only for a single locale - // that is specified in `i18n.locale` config value. + handler: async (request, h) => { const { locale } = request.params; - if (i18n.getLocale() !== locale.toLowerCase()) { - throw Boom.notFound(`Unknown locale: ${locale}`); + const normalizedLocale = locale.toLowerCase(); + const registeredLocales = i18nLoader.getRegisteredLocales().map((l) => l.toLowerCase()); + let warning = null; + + // Function to get or create cached translations + const getCachedTranslations = async (localeKey, getTranslationsFn) => { + if (!translationsCache[localeKey]) { + const translations = await getTranslationsFn(); + translationsCache[localeKey] = { + translations: translations, + hash: createHash('sha1').update(JSON.stringify(translations)).digest('hex'), + }; + } + return translationsCache[localeKey]; + }; + + let cachedTranslations; + + if (normalizedLocale === defaultLocale.toLowerCase()) { + // Default locale + cachedTranslations = await getCachedTranslations(defaultLocale, () => + i18n.getTranslation() + ); + } else if (registeredLocales.includes(normalizedLocale)) { + // Other registered locales + cachedTranslations = await getCachedTranslations(normalizedLocale, () => + i18nLoader.getTranslationsByLocale(locale) + ); + } else { + // Locale not found, fall back to en locale + cachedTranslations = await getCachedTranslations('en', () => + i18nLoader.getTranslationsByLocale('en') + ); + warning = { + title: 'Unsupported Locale', + text: `The requested locale "${locale}" is not supported. Falling back to English.`, + }; } - // Stringifying thousands of labels and calculating hash on the resulting - // string can be expensive so it makes sense to do it once and cache. - if (translationsCache.translations == null) { - translationsCache.translations = JSON.stringify(i18n.getTranslation()); - translationsCache.hash = createHash('sha1') - .update(translationsCache.translations) - .digest('hex'); - } + const response = { + translations: cachedTranslations.translations, + warning, + }; return h - .response(translationsCache.translations) + .response(response) .header('cache-control', 'must-revalidate') .header('content-type', 'application/json') - .etag(translationsCache.hash); + .etag(cachedTranslations.hash); }, }); diff --git a/src/legacy/ui/ui_render/ui_render_mixin.test.js b/src/legacy/ui/ui_render/ui_render_mixin.test.js new file mode 100644 index 000000000000..81f8a9f9a696 --- /dev/null +++ b/src/legacy/ui/ui_render/ui_render_mixin.test.js @@ -0,0 +1,175 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { uiRenderMixin } from './ui_render_mixin'; + +// Mock dependencies +jest.mock('@osd/i18n', () => ({ + i18n: { + getLocale: jest.fn(), + getTranslation: jest.fn(), + translate: jest.fn((key, { defaultMessage }) => defaultMessage), + }, + i18nLoader: { + getRegisteredLocales: jest.fn(), + getTranslationsByLocale: jest.fn(), + }, +})); + +// Import mocked modules +const { i18n, i18nLoader } = require('@osd/i18n'); + +describe('uiRenderMixin', () => { + let server; + let osdServer; + let config; + let routes; + let decorations; + + beforeEach(() => { + routes = []; + decorations = {}; + server = { + route: jest.fn((route) => routes.push(route)), + decorate: jest.fn((type, name, value) => { + decorations[`${type}.${name}`] = value; + }), + auth: { settings: { default: false } }, + }; + osdServer = { + newPlatform: { + setup: { + core: { + http: { csp: { header: 'test-csp-header' } }, + }, + }, + start: { + core: { + savedObjects: { + getScopedClient: jest.fn(), + }, + uiSettings: { + asScopedToClient: jest.fn(), + }, + }, + }, + __internals: { + rendering: { + render: jest.fn(), + }, + }, + }, + }; + config = { + get: jest.fn(), + }; + + // Reset mocks + jest.clearAllMocks(); + }); + + describe('translations route', () => { + let handler; + let h; + + beforeEach(() => { + uiRenderMixin(osdServer, server, config); + handler = routes.find((route) => route.path === '/translations/{locale}.json').handler; + h = { + response: jest.fn().mockReturnThis(), + header: jest.fn().mockReturnThis(), + etag: jest.fn().mockReturnThis(), + }; + }); + + it('should handle default locale', async () => { + const defaultLocale = 'en'; + const defaultTranslations = { hello: 'Hello' }; + i18n.getLocale.mockReturnValue(defaultLocale); + i18n.getTranslation.mockReturnValue(defaultTranslations); + i18nLoader.getRegisteredLocales.mockReturnValue([defaultLocale]); + + const request = { params: { locale: defaultLocale } }; + await handler(request, h); + + expect(i18n.getTranslation).toHaveBeenCalled(); + expect(h.response).toHaveBeenCalledWith({ + translations: defaultTranslations, + warning: null, + }); + expect(h.header).toHaveBeenCalledWith('cache-control', 'must-revalidate'); + expect(h.header).toHaveBeenCalledWith('content-type', 'application/json'); + expect(h.etag).toHaveBeenCalled(); + }); + + it('should handle non-default registered locale', async () => { + const defaultLocale = 'en'; + const requestedLocale = 'fr'; + const frTranslations = { hello: 'Bonjour' }; + i18n.getLocale.mockReturnValue(defaultLocale); + i18nLoader.getRegisteredLocales.mockReturnValue([defaultLocale, requestedLocale]); + i18nLoader.getTranslationsByLocale.mockResolvedValue(frTranslations); + + const request = { params: { locale: requestedLocale } }; + await handler(request, h); + + expect(i18nLoader.getTranslationsByLocale).toHaveBeenCalledWith(requestedLocale); + expect(h.response).toHaveBeenCalledWith({ + translations: frTranslations, + warning: null, + }); + }); + + it('should fallback to English translations for unknown locale', async () => { + const defaultLocale = 'en'; + const unknownLocale = 'xx'; + const englishTranslations = { hello: 'Hello' }; + i18n.getLocale.mockReturnValue(defaultLocale); + i18nLoader.getRegisteredLocales.mockReturnValue([defaultLocale]); + i18nLoader.getTranslationsByLocale.mockResolvedValue(englishTranslations); + + const request = { params: { locale: unknownLocale } }; + await handler(request, h); + + expect(i18nLoader.getTranslationsByLocale).toHaveBeenCalledWith('en'); + expect(h.response).toHaveBeenCalledWith({ + translations: englishTranslations, + warning: { + title: 'Unsupported Locale', + text: `The requested locale "${unknownLocale}" is not supported. Falling back to English.`, + }, + }); + expect(h.header).toHaveBeenCalledWith('cache-control', 'must-revalidate'); + expect(h.header).toHaveBeenCalledWith('content-type', 'application/json'); + expect(h.etag).toHaveBeenCalled(); + }); + + it('should cache translations', async () => { + const defaultLocale = 'en'; + const defaultTranslations = { hello: 'Hello' }; + i18n.getLocale.mockReturnValue(defaultLocale); + i18n.getTranslation.mockReturnValue(defaultTranslations); + i18nLoader.getRegisteredLocales.mockReturnValue([defaultLocale]); + + const request = { params: { locale: defaultLocale } }; + await handler(request, h); + await handler(request, h); + + expect(i18n.getTranslation).toHaveBeenCalledTimes(1); + }); + + it('should handle errors gracefully', async () => { + const defaultLocale = 'en'; + i18n.getLocale.mockReturnValue(defaultLocale); + i18n.getTranslation.mockImplementation(() => { + throw new Error('Translation error'); + }); + i18nLoader.getRegisteredLocales.mockReturnValue([defaultLocale]); + + const request = { params: { locale: defaultLocale } }; + await expect(handler(request, h)).rejects.toThrow('Translation error'); + }); + }); +}); From 179b37aea0c83de94944b242545eb7a32628245d Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 22:30:28 -0700 Subject: [PATCH 223/276] [Workspace] Updated permission settings appearance (#7652) (#7784) * Changed permission control style * Merged the group section and user section, and added type switching. * Added isDisabled for permission control * Modified styles and added descriptions for permission control * / * Modified tests * Changeset file for PR #7652 created/updated * Modified tests * Modified tests * / * Modified tests * Remove the doc updates * Remove the doc updates * Resolve some issues * resolve some issues * Change type switch to popover style * Change type switch to popover style * Change type switch to popover style * Change type switch to popover style * Modify tests * Resolve some issues * Modify tests * Modify tests to increase coverage * Modify tests * Modify tests * Modify tests * Modify tests --------- (cherry picked from commit aed03fa1986b980279644778b8ff98c3233f113c) Signed-off-by: Kapian1234 Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7652.yml | 2 + .../workspace_creator.test.tsx | 2 +- .../components/workspace_form/constants.ts | 5 + .../workspace_form/workspace_form.tsx | 16 +- ...orkspace_permission_setting_input.test.tsx | 62 ++++-- .../workspace_permission_setting_input.tsx | 172 ++++++++++++----- ...orkspace_permission_setting_panel.test.tsx | 119 ++++++++++-- .../workspace_permission_setting_panel.tsx | 176 ++++++------------ 8 files changed, 354 insertions(+), 200 deletions(-) create mode 100644 changelogs/fragments/7652.yml diff --git a/changelogs/fragments/7652.yml b/changelogs/fragments/7652.yml new file mode 100644 index 000000000000..132afc64c12c --- /dev/null +++ b/changelogs/fragments/7652.yml @@ -0,0 +1,2 @@ +feat: +- Update permission settings appearance ([#7652](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7652)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx index e3463bc7d9f5..f42665acd1d1 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx @@ -252,7 +252,7 @@ describe('WorkspaceCreator', () => { target: { value: 'test workspace name' }, }); fireEvent.click(getByTestId('workspaceUseCase-observability')); - fireEvent.click(getByTestId('workspaceForm-permissionSettingPanel-user-addNew')); + fireEvent.click(getByTestId('workspaceForm-permissionSettingPanel-addNew')); fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); expect(workspaceClientCreate).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/src/plugins/workspace/public/components/workspace_form/constants.ts b/src/plugins/workspace/public/components/workspace_form/constants.ts index a69afeacbbbc..1224d5abb0ec 100644 --- a/src/plugins/workspace/public/components/workspace_form/constants.ts +++ b/src/plugins/workspace/public/components/workspace_form/constants.ts @@ -49,6 +49,11 @@ export const usersAndPermissionsTitle = i18n.translate('workspace.form.usersAndP defaultMessage: 'Workspaces access', }); +export const usersAndPermissionsCreatePageTitle = i18n.translate( + 'workspace.form.usersAndPermissions.createPage.title', + { defaultMessage: 'Add collaborators' } +); + export const detailsName = i18n.translate('workspace.form.workspaceDetails.name.label', { defaultMessage: 'Name', }); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index a968f560fb03..04e232736e2a 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -4,8 +4,8 @@ */ import React, { useRef } from 'react'; -import { EuiPanel, EuiSpacer, EuiTitle, EuiForm } from '@elastic/eui'; - +import { EuiPanel, EuiSpacer, EuiTitle, EuiForm, EuiText } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; import { WorkspaceFormProps } from './types'; import { useWorkspaceForm } from './use_workspace_form'; import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; @@ -16,7 +16,7 @@ import { SelectDataSourcePanel } from './select_data_source_panel'; import { EnterDetailsPanel } from './workspace_enter_details_panel'; import { selectDataSourceTitle, - usersAndPermissionsTitle, + usersAndPermissionsCreatePageTitle, workspaceDetailsTitle, workspaceUseCaseTitle, } from './constants'; @@ -36,7 +36,6 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { formData, formErrors, numberOfErrors, - numberOfChanges, setName, setDescription, handleFormSubmit, @@ -95,8 +94,15 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { {permissionEnabled && ( -

    {usersAndPermissionsTitle}

    +

    {usersAndPermissionsCreatePageTitle}

    + + + {i18n.translate('workspace.form.usersAndPermissions.description', { + defaultMessage: + 'You will be added as an owner to the workspace. Select additional users and user groups as workspace collaborators with different access levels.', + })} + ) => { const onGroupOrUserIdChangeMock = jest.fn(); const onPermissionModesChangeMock = jest.fn(); const onDeleteMock = jest.fn(); + const onTypeChangeMock = jest.fn(); const renderResult = render( ) => { onGroupOrUserIdChange={onGroupOrUserIdChangeMock} onPermissionModesChange={onPermissionModesChangeMock} onDelete={onDeleteMock} + onTypeChange={onTypeChangeMock} {...options} /> ); @@ -32,10 +34,41 @@ const setup = (options?: Partial) => { onGroupOrUserIdChangeMock, onPermissionModesChangeMock, onDeleteMock, + onTypeChangeMock, }; }; describe('WorkspacePermissionSettingInput', () => { + const originalOffsetHeight = Object.getOwnPropertyDescriptor( + HTMLElement.prototype, + 'offsetHeight' + ); + const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetWidth'); + + beforeEach(() => { + Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { + configurable: true, + value: 600, + }); + Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { + configurable: true, + value: 600, + }); + }); + + afterEach(() => { + Object.defineProperty( + HTMLElement.prototype, + 'offsetHeight', + originalOffsetHeight as PropertyDescriptor + ); + Object.defineProperty( + HTMLElement.prototype, + 'offsetWidth', + originalOffsetWidth as PropertyDescriptor + ); + }); + it('should render consistent user id and permission modes', () => { const { renderResult } = setup({ userId: 'foo', @@ -44,9 +77,6 @@ describe('WorkspacePermissionSettingInput', () => { expect(renderResult.getByText('foo')).toBeInTheDocument(); expect(renderResult.getByText('Read')).toBeInTheDocument(); - expect( - renderResult.getByText('Read').closest('.euiButtonGroupButton-isSelected') - ).toBeInTheDocument(); }); it('should render consistent group id and permission modes', () => { const { renderResult } = setup({ @@ -57,19 +87,16 @@ describe('WorkspacePermissionSettingInput', () => { expect(renderResult.getByText('bar')).toBeInTheDocument(); expect(renderResult.getByText('Read & Write')).toBeInTheDocument(); - expect( - renderResult.getByText('Read & Write').closest('.euiButtonGroupButton-isSelected') - ).toBeInTheDocument(); }); it('should call onGroupOrUserIdChange with user id', () => { const { renderResult, onGroupOrUserIdChangeMock } = setup(); expect(onGroupOrUserIdChangeMock).not.toHaveBeenCalled(); fireEvent.click(renderResult.getByText('Select a user')); - fireEvent.input(renderResult.getByTestId('comboBoxSearchInput'), { + fireEvent.input(renderResult.getAllByTestId('comboBoxSearchInput')[0], { target: { value: 'user1' }, }); - fireEvent.blur(renderResult.getByTestId('comboBoxSearchInput')); + fireEvent.blur(renderResult.getAllByTestId('comboBoxSearchInput')[0]); expect(onGroupOrUserIdChangeMock).toHaveBeenCalledWith({ type: 'user', userId: 'user1' }, 0); }); it('should call onGroupOrUserIdChange with group', () => { @@ -79,10 +106,10 @@ describe('WorkspacePermissionSettingInput', () => { expect(onGroupOrUserIdChangeMock).not.toHaveBeenCalled(); fireEvent.click(renderResult.getByText('Select a user group')); - fireEvent.input(renderResult.getByTestId('comboBoxSearchInput'), { + fireEvent.input(renderResult.getAllByTestId('comboBoxSearchInput')[0], { target: { value: 'group' }, }); - fireEvent.blur(renderResult.getByTestId('comboBoxSearchInput')); + fireEvent.blur(renderResult.getAllByTestId('comboBoxSearchInput')[0]); expect(onGroupOrUserIdChangeMock).toHaveBeenCalledWith({ type: 'group', group: 'group' }, 0); }); @@ -100,6 +127,10 @@ describe('WorkspacePermissionSettingInput', () => { const { renderResult, onPermissionModesChangeMock } = setup({}); expect(onPermissionModesChangeMock).not.toHaveBeenCalled(); + const permissionToggleListButton = within( + renderResult.getAllByTestId('workspace-permissionModeOptions')[0] + ).getByTestId('comboBoxToggleListButton'); + fireEvent.click(permissionToggleListButton); fireEvent.click(renderResult.getByText('Owner')); expect(onPermissionModesChangeMock).toHaveBeenCalledWith(['library_write', 'write'], 0); }); @@ -111,4 +142,13 @@ describe('WorkspacePermissionSettingInput', () => { fireEvent.click(renderResult.getByLabelText('Delete permission setting')); expect(onDeleteMock).toHaveBeenCalledWith(0); }); + + it('should call onTypeChange with types after types changed', () => { + const { renderResult, onTypeChangeMock } = setup({}); + expect(onTypeChangeMock).not.toHaveBeenCalled(); + + fireEvent.click(renderResult.getByTestId('workspace-typeOptions')); + fireEvent.click(renderResult.getByText('Group')); + expect(onTypeChangeMock).toHaveBeenCalledWith('group', 0); + }); }); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx index 40165530c3b2..96c79b5b26da 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx @@ -3,14 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { EuiFlexGroup, - EuiCompressedComboBox, EuiFlexItem, + EuiComboBox, + EuiPopover, EuiButtonIcon, - EuiButtonGroup, - EuiText, + EuiButtonEmpty, + EuiSelectable, + EuiComboBoxOptionOption, + EuiSelectableOption, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { WorkspacePermissionMode } from '../../../common/constants'; @@ -23,37 +26,25 @@ import { getPermissionModeId } from './utils'; const permissionModeOptions = [ { - id: PermissionModeId.Read, - label: ( - - {i18n.translate('workspace.form.permissionSettingPanel.permissionModeOptions.read', { - defaultMessage: 'Read', - })} - - ), + value: PermissionModeId.Read, + label: i18n.translate('workspace.form.permissionSettingPanel.permissionModeOptions.read', { + defaultMessage: 'Read', + }), }, { - id: PermissionModeId.ReadAndWrite, - label: ( - - {i18n.translate( - 'workspace.form.permissionSettingPanel.permissionModeOptions.readAndWrite', - { - defaultMessage: 'Read & Write', - } - )} - + value: PermissionModeId.ReadAndWrite, + label: i18n.translate( + 'workspace.form.permissionSettingPanel.permissionModeOptions.readAndWrite', + { + defaultMessage: 'Read & Write', + } ), }, { - id: PermissionModeId.Owner, - label: ( - - {i18n.translate('workspace.form.permissionSettingPanel.permissionModeOptions.owner', { - defaultMessage: 'Owner', - })} - - ), + value: PermissionModeId.Owner, + label: i18n.translate('workspace.form.permissionSettingPanel.permissionModeOptions.owner', { + defaultMessage: 'Owner', + }), }, ]; @@ -67,13 +58,14 @@ export interface WorkspacePermissionSettingInputProps { deletable?: boolean; userOrGroupDisabled: boolean; onGroupOrUserIdChange: ( - groupOrUserId: + id: | { type: WorkspacePermissionItemType.User; userId?: string } | { type: WorkspacePermissionItemType.Group; group?: string }, index: number ) => void; - onPermissionModesChange: ( - WorkspacePermissionMode: WorkspacePermissionMode[], + onPermissionModesChange: (modes: WorkspacePermissionMode[], index: number) => void; + onTypeChange: ( + type: WorkspacePermissionItemType.User | WorkspacePermissionItemType.Group, index: number ) => void; onDelete: (index: number) => void; @@ -91,13 +83,43 @@ export const WorkspacePermissionSettingInput = ({ onDelete, onGroupOrUserIdChange, onPermissionModesChange, + onTypeChange, }: WorkspacePermissionSettingInputProps) => { const groupOrUserIdSelectedOptions = useMemo( () => (group || userId ? [{ label: (group || userId) as string }] : []), [group, userId] ); - const permissionModesSelectedId = useMemo(() => getPermissionModeId(modes ?? []), [modes]); + const [isTypeListOpen, setIsTypeListOpen] = useState(false); + + const typeOptions = useMemo>>( + () => [ + { + value: WorkspacePermissionItemType.User, + label: i18n.translate('workspace.form.permissionSettingPanel.typeOptions.user', { + defaultMessage: 'User', + }), + checked: type === WorkspacePermissionItemType.User ? 'on' : undefined, + }, + { + value: WorkspacePermissionItemType.Group, + label: i18n.translate('workspace.form.permissionSettingPanel.typeOptions.group', { + defaultMessage: 'Group', + }), + checked: type === WorkspacePermissionItemType.Group ? 'on' : undefined, + }, + ], + [type] + ); + + const permissionModesSelected = useMemo(() => { + const idSelected = getPermissionModeId(modes ?? []); + const permissionModeSelected = permissionModeOptions.find( + (option) => option.value === idSelected + ); + return permissionModeSelected ? [permissionModeSelected] : []; + }, [modes]); + const handleGroupOrUserIdCreate = useCallback( (groupOrUserId) => { onGroupOrUserIdChange( @@ -111,7 +133,7 @@ export const WorkspacePermissionSettingInput = ({ ); const handleGroupOrUserIdChange = useCallback( - (options) => { + (options: Array>) => { if (options.length === 0) { onGroupOrUserIdChange({ type }, index); } @@ -120,23 +142,40 @@ export const WorkspacePermissionSettingInput = ({ ); const handlePermissionModeOptionChange = useCallback( - (id: string) => { - if (optionIdToWorkspacePermissionModesMap[id]) { - onPermissionModesChange([...optionIdToWorkspacePermissionModesMap[id]], index); + (option: Array>) => { + if (option.length > 0) { + const id = option[0].value; + if (optionIdToWorkspacePermissionModesMap[id]) { + onPermissionModesChange([...optionIdToWorkspacePermissionModesMap[id]], index); + } } }, [index, onPermissionModesChange] ); + const handleTypeChange = useCallback( + (options: Array>) => { + for (const option of options) { + if (option.checked === 'on') { + onTypeChange(option.value, index); + setIsTypeListOpen(false); + return; + } + } + }, + [index, onTypeChange] + ); + const handleDelete = useCallback(() => { onDelete(index); }, [index, onDelete]); return ( - + - setIsTypeListOpen((current) => !current)} + data-test-subj="workspace-typeOptions" + isDisabled={userOrGroupDisabled || !isEditing} + > + {type === WorkspacePermissionItemType.User + ? typeOptions[0].label + : typeOptions[1].label} + + } + isOpen={isTypeListOpen} + closePopover={() => setIsTypeListOpen(false)} + panelPaddingSize="none" + > + + {(list) => list} + + + } /> - - + @@ -170,7 +242,7 @@ export const WorkspacePermissionSettingInput = ({ color="danger" aria-label="Delete permission setting" iconType="trash" - display="base" + display="empty" size="m" onClick={handleDelete} isDisabled={!deletable} diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx index 6e8a3ffb62dc..5dccb1831339 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx @@ -4,7 +4,7 @@ */ import React from 'react'; -import { fireEvent, render } from '@testing-library/react'; +import { fireEvent, render, waitFor, within } from '@testing-library/react'; import { WorkspacePermissionSettingPanel, WorkspacePermissionSettingPanelProps, @@ -43,25 +43,55 @@ const setup = (options?: Partial) => { }; describe('WorkspacePermissionSettingInput', () => { + const originalOffsetHeight = Object.getOwnPropertyDescriptor( + HTMLElement.prototype, + 'offsetHeight' + ); + const originalOffsetWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetWidth'); + + beforeEach(() => { + Object.defineProperty(HTMLElement.prototype, 'offsetHeight', { + configurable: true, + value: 600, + }); + Object.defineProperty(HTMLElement.prototype, 'offsetWidth', { + configurable: true, + value: 600, + }); + }); + + afterEach(() => { + Object.defineProperty( + HTMLElement.prototype, + 'offsetHeight', + originalOffsetHeight as PropertyDescriptor + ); + Object.defineProperty( + HTMLElement.prototype, + 'offsetWidth', + originalOffsetWidth as PropertyDescriptor + ); + }); + it('should render consistent user and group permissions', () => { const { renderResult } = setup(); expect(renderResult.getByText('foo')).toBeInTheDocument(); - expect( - renderResult.getAllByText('Read')[0].closest('.euiButtonGroupButton-isSelected') - ).toBeInTheDocument(); + expect(renderResult.getByText('Read')).toBeInTheDocument(); expect(renderResult.getByText('bar')).toBeInTheDocument(); - expect( - renderResult.getAllByText('Read & Write')[1].closest('.euiButtonGroupButton-isSelected') - ).toBeInTheDocument(); + expect(renderResult.getByText('Read & Write')).toBeInTheDocument(); }); it('should call onChange with new user permission modes', () => { const { renderResult, onChangeMock } = setup(); expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getAllByText('Read & Write')[0]); + const permissionToggleListButton = within( + renderResult.getAllByTestId('workspace-permissionModeOptions')[0] + ).getByTestId('comboBoxToggleListButton'); + fireEvent.click(permissionToggleListButton); + fireEvent.click(renderResult.getAllByText('Read & Write')[1]); expect(onChangeMock).toHaveBeenCalledWith([ { id: 0, @@ -81,7 +111,11 @@ describe('WorkspacePermissionSettingInput', () => { const { renderResult, onChangeMock } = setup(); expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getAllByText('Owner')[1]); + const permissionToggleListButton = within( + renderResult.getAllByTestId('workspace-permissionModeOptions')[1] + ).getByTestId('comboBoxToggleListButton'); + fireEvent.click(permissionToggleListButton); + fireEvent.click(renderResult.getByText('Owner')); expect(onChangeMock).toHaveBeenCalledWith([ { id: 0, @@ -97,6 +131,50 @@ describe('WorkspacePermissionSettingInput', () => { }, ]); }); + it('should call onChange with new user type', () => { + const { renderResult, onChangeMock } = setup(); + expect(onChangeMock).not.toHaveBeenCalled(); + + waitFor(() => { + fireEvent.click(renderResult.getAllByTestId('workspace-typeOptions')[1]); + fireEvent.click(renderResult.getAllByText('User')[1]); + expect(onChangeMock).toHaveBeenCalledWith([ + { + id: 0, + type: WorkspacePermissionItemType.User, + userId: 'foo', + modes: ['library_read', 'read'], + }, + { + id: 1, + type: WorkspacePermissionItemType.User, + modes: ['library_write', 'read'], + }, + ]); + }); + }); + it('should call onChange with new group type', () => { + const { renderResult, onChangeMock } = setup(); + + expect(onChangeMock).not.toHaveBeenCalled(); + waitFor(() => { + fireEvent.click(renderResult.getAllByTestId('workspace-typeOptions')[0]); + fireEvent.click(renderResult.getAllByText('Group')[0]); + expect(onChangeMock).toHaveBeenCalledWith([ + { + id: 0, + type: WorkspacePermissionItemType.Group, + modes: ['library_read', 'read'], + }, + { + id: 1, + type: WorkspacePermissionItemType.Group, + group: 'bar', + modes: ['library_write', 'read'], + }, + ]); + }); + }); it('should call onChange with new user permission setting after add new button click', () => { const { renderResult, onChangeMock } = setup({ @@ -104,7 +182,7 @@ describe('WorkspacePermissionSettingInput', () => { }); expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getByTestId('workspaceForm-permissionSettingPanel-user-addNew')); + fireEvent.click(renderResult.getByTestId('workspaceForm-permissionSettingPanel-addNew')); expect(onChangeMock).toHaveBeenCalledWith([ { id: 0, @@ -114,22 +192,29 @@ describe('WorkspacePermissionSettingInput', () => { ]); }); - it('should call onChange with new group permission setting after add new button click', () => { - const { renderResult, onChangeMock } = setup({ - permissionSettings: [], - }); + it('should call onChange with user permission setting after delete button click', () => { + const { renderResult, onChangeMock } = setup(); expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getByTestId('workspaceForm-permissionSettingPanel-group-addNew')); + fireEvent.click(renderResult.getAllByLabelText('Delete permission setting')[0]); expect(onChangeMock).toHaveBeenCalledWith([ { - id: 0, + id: 1, type: WorkspacePermissionItemType.Group, - modes: [WorkspacePermissionMode.LibraryRead, WorkspacePermissionMode.Read], + group: 'bar', + modes: [WorkspacePermissionMode.LibraryWrite, WorkspacePermissionMode.Read], }, ]); }); + it('should call onGroupOrUserIdChange without user id after clear button clicked', () => { + const { renderResult, onChangeMock } = setup(); + + expect(onChangeMock).not.toHaveBeenCalled(); + fireEvent.click(renderResult.getAllByTestId('comboBoxClearButton')[0]); + expect(onChangeMock).toHaveBeenCalled(); + }); + it('should not able to edit user or group when disabled', () => { const { renderResult } = setup({ permissionSettings: [ diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.tsx index b9027697dee4..951615279d94 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useCallback, useEffect, useMemo, useRef } from 'react'; +import React, { useCallback, useEffect, useRef } from 'react'; import { EuiSmallButton, EuiFlexGroup, @@ -36,57 +36,74 @@ export interface WorkspacePermissionSettingPanelProps { isEditing?: boolean; } -interface UserOrGroupSectionProps extends WorkspacePermissionSettingPanelProps { - type: WorkspacePermissionItemType; - nextIdGenerator: () => number; -} - -const UserOrGroupSection = ({ - type, +export const WorkspacePermissionSettingPanel = ({ errors, onChange, - isEditing, - nextIdGenerator, + isEditing = true, permissionSettings, disabledUserOrGroupInputIds, -}: UserOrGroupSectionProps) => { +}: WorkspacePermissionSettingPanelProps) => { + const nextIdRef = useRef(generateNextPermissionSettingsId(permissionSettings)); + + const handlePermissionSettingsChange = useCallback( + (newSettings) => { + onChange?.([...newSettings]); + }, + [onChange] + ); + + const nextIdGenerator = useCallback(() => { + const nextId = nextIdRef.current; + nextIdRef.current++; + return nextId; + }, []); + + useEffect(() => { + nextIdRef.current = Math.max( + nextIdRef.current, + generateNextPermissionSettingsId(permissionSettings) + ); + }, [permissionSettings]); + // default permission mode is read const handleAddNewOne = useCallback(() => { - onChange?.([ + handlePermissionSettingsChange?.([ ...permissionSettings, { id: nextIdGenerator(), - type, + type: WorkspacePermissionItemType.User, modes: optionIdToWorkspacePermissionModesMap[PermissionModeId.Read], }, ]); - }, [onChange, type, permissionSettings, nextIdGenerator]); + }, [handlePermissionSettingsChange, permissionSettings, nextIdGenerator]); const handleDelete = useCallback( (index: number) => { - onChange?.(permissionSettings.filter((_item, itemIndex) => itemIndex !== index)); + handlePermissionSettingsChange?.( + permissionSettings.filter((_item, itemIndex) => itemIndex !== index) + ); }, - [onChange, permissionSettings] + [handlePermissionSettingsChange, permissionSettings] ); const handlePermissionModesChange = useCallback< WorkspacePermissionSettingInputProps['onPermissionModesChange'] >( (modes, index) => { - onChange?.( + handlePermissionSettingsChange?.( permissionSettings.map((item, itemIndex) => index === itemIndex ? { ...item, modes } : item ) ); }, - [onChange, permissionSettings] + [handlePermissionSettingsChange, permissionSettings] ); const handleGroupOrUserIdChange = useCallback< WorkspacePermissionSettingInputProps['onGroupOrUserIdChange'] >( (userOrGroupIdWithType, index) => { - onChange?.( + handlePermissionSettingsChange?.( permissionSettings.map((item, itemIndex) => index === itemIndex ? { @@ -98,7 +115,18 @@ const UserOrGroupSection = ({ ) ); }, - [onChange, permissionSettings] + [handlePermissionSettingsChange, permissionSettings] + ); + + const handleTypeChange = useCallback( + (type, index) => { + handlePermissionSettingsChange?.( + permissionSettings.map((item, itemIndex) => + index === itemIndex ? { id: item.id, type, modes: item.modes } : item + ) + ); + }, + [handlePermissionSettingsChange, permissionSettings] ); return ( @@ -106,15 +134,9 @@ const UserOrGroupSection = ({ <> @@ -122,7 +144,7 @@ const UserOrGroupSection = ({ <> @@ -139,12 +161,13 @@ const UserOrGroupSection = ({ > @@ -154,94 +177,15 @@ const UserOrGroupSection = ({ - {type === WorkspacePermissionItemType.User - ? i18n.translate('workspace.form.permissionSettingPanel.addUser', { - defaultMessage: 'Add user', - }) - : i18n.translate('workspace.form.permissionSettingPanel.addUserGroup', { - defaultMessage: 'Add user group', - })} + {i18n.translate('workspace.form.permissionSettingPanel.addCollaborator', { + defaultMessage: 'Add collaborator', + })} )}
    ); }; - -export const WorkspacePermissionSettingPanel = ({ - errors, - onChange, - permissionSettings, - disabledUserOrGroupInputIds, - isEditing = true, -}: WorkspacePermissionSettingPanelProps) => { - const userPermissionSettings = useMemo( - () => - permissionSettings?.filter( - (permissionSettingItem) => permissionSettingItem.type === WorkspacePermissionItemType.User - ) ?? [], - [permissionSettings] - ); - const groupPermissionSettings = useMemo( - () => - permissionSettings?.filter( - (permissionSettingItem) => permissionSettingItem.type === WorkspacePermissionItemType.Group - ) ?? [], - [permissionSettings] - ); - - const nextIdRef = useRef(generateNextPermissionSettingsId(permissionSettings)); - - const handleUserPermissionSettingsChange = useCallback( - (newSettings) => { - onChange?.([...newSettings, ...groupPermissionSettings]); - }, - [groupPermissionSettings, onChange] - ); - - const handleGroupPermissionSettingsChange = useCallback( - (newSettings) => { - onChange?.([...userPermissionSettings, ...newSettings]); - }, - [userPermissionSettings, onChange] - ); - - const nextIdGenerator = useCallback(() => { - const nextId = nextIdRef.current; - nextIdRef.current++; - return nextId; - }, []); - - useEffect(() => { - nextIdRef.current = Math.max( - nextIdRef.current, - generateNextPermissionSettingsId(permissionSettings) - ); - }, [permissionSettings]); - - return ( -
    - - - -
    - ); -}; From 26ebcd1a950cf5f285f8b07ff94e48e29f238fb0 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 23:25:45 -0700 Subject: [PATCH 224/276] Fix new header allowing their single-child's overflowing (#7796) (#7798) * Fix new header allowing their single-child's overflowing * Changeset file for PR #7796 created/updated --------- (cherry picked from commit 8d3f8d5be010e9762aa602fb957173a10ff63fcb) Signed-off-by: Miki Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7796.yml | 2 ++ src/core/public/chrome/ui/header/header.scss | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 changelogs/fragments/7796.yml diff --git a/changelogs/fragments/7796.yml b/changelogs/fragments/7796.yml new file mode 100644 index 000000000000..1e17933facf9 --- /dev/null +++ b/changelogs/fragments/7796.yml @@ -0,0 +1,2 @@ +fix: +- Fix new header allowing their single-child's overflowing ([#7796](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7796)) \ No newline at end of file diff --git a/src/core/public/chrome/ui/header/header.scss b/src/core/public/chrome/ui/header/header.scss index 8828679e7284..f8da8a809d70 100644 --- a/src/core/public/chrome/ui/header/header.scss +++ b/src/core/public/chrome/ui/header/header.scss @@ -49,6 +49,10 @@ & > .euiHeaderSection { gap: $euiSizeS; + &:only-child { + width: 100%; + } + // stylelint-disable-next-line @osd/stylelint/no_modifying_global_selectors & > .euiHeaderSectionItem:empty { display: none; From a9cfba028fff80a6b1be87ca858bb5ec8134455f Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:20:40 +0800 Subject: [PATCH 225/276] Add `iconGap` to `TopNavControlButtonData` abd `TopNavControlLinkData` (#7799) (#7800) * Bump OUI to 1.11.0 * Update snapshots for OUI 1.11.0 * Add `iconGap` to `TopNavControlButtonData` abd `TopNavControlLinkData` * Changeset file for PR #7799 created/updated * Changeset file for PR #7799 created/updated --------- (cherry picked from commit 3a41f7bb480ddad30edef4cf2c6cfdd55f49ab73) Signed-off-by: Miki Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7799.yml | 4 ++++ package.json | 2 +- packages/osd-ui-framework/package.json | 2 +- packages/osd-ui-shared-deps/package.json | 2 +- .../header/__snapshots__/header.test.tsx.snap | 11 ++++++++++ .../header_help_menu.test.tsx.snap | 9 ++++++++ .../__snapshots__/import_flyout.test.tsx.snap | 2 ++ .../__snapshots__/create_button.test.tsx.snap | 2 ++ .../dashboard_empty_screen.test.tsx.snap | 1 + .../get_no_items_message.test.tsx.snap | 1 + .../language_selector.test.tsx.snap | 2 ++ .../data_source_table.test.tsx.snap | 9 ++++++++ ...review_amazon_s3_data_source.test.tsx.snap | 1 + ...eview_prometheus_data_source.test.tsx.snap | 1 + .../available_integration_table.test.tsx.snap | 4 ++++ ...installed_integrations_table.test.tsx.snap | 2 ++ .../setup_integration.test.tsx.snap | 2 ++ .../update_password_modal.test.tsx.snap | 2 ++ .../saved_objects_installer.test.js.snap | 2 ++ .../inspector_panel.test.tsx.snap | 1 + .../top_nav_menu/top_nav_control_data.tsx | 2 ++ .../top_nav_menu/top_nav_control_item.tsx | 22 ++++++++++++++++--- .../__snapshots__/header.test.tsx.snap | 2 ++ .../__snapshots__/new_vis_modal.test.tsx.snap | 2 ++ .../plugins/osd_tp_run_pipeline/package.json | 2 +- .../osd_sample_panel_action/package.json | 2 +- .../osd_tp_custom_visualizations/package.json | 2 +- yarn.lock | 8 +++---- 28 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 changelogs/fragments/7799.yml diff --git a/changelogs/fragments/7799.yml b/changelogs/fragments/7799.yml new file mode 100644 index 000000000000..15d74ab2efde --- /dev/null +++ b/changelogs/fragments/7799.yml @@ -0,0 +1,4 @@ +feat: +- Add external icon to `TopNavControlButtonData` and `TopNavControlLinkData` with `target: '_blank'` ([#7799](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7799)) +- Add `iconGap` to `TopNavControlButtonData` and `TopNavControlLinkData` ([#7799](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7799)) +- Bump OUI to 1.11.0 ([#7799](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7799)) \ No newline at end of file diff --git a/package.json b/package.json index 0fc7f728ac39..420c19f30f6a 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "dependencies": { "@aws-crypto/client-node": "^3.1.1", "@elastic/datemath": "5.0.3", - "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", "@elastic/good": "^9.0.1-kibana3", "@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0", "@elastic/request-crypto": "2.0.0", diff --git a/packages/osd-ui-framework/package.json b/packages/osd-ui-framework/package.json index 3088d58f07ec..a2df7f94869f 100644 --- a/packages/osd-ui-framework/package.json +++ b/packages/osd-ui-framework/package.json @@ -23,7 +23,7 @@ "enzyme-adapter-react-16": "^1.9.1" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", "@osd/babel-preset": "1.0.0", "@osd/optimizer": "1.0.0", "comment-stripper": "^0.0.4", diff --git a/packages/osd-ui-shared-deps/package.json b/packages/osd-ui-shared-deps/package.json index fc7da1d3b91f..4f3af509c5b0 100644 --- a/packages/osd-ui-shared-deps/package.json +++ b/packages/osd-ui-shared-deps/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@elastic/charts": "31.1.0", - "@elastic/eui": "npm:@opensearch-project/oui@1.10.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", "@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0", "@opensearch/datemath": "5.0.3", "@osd/i18n": "1.0.0", diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index 219c5dd3d389..168407a7de4f 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -3353,6 +3353,7 @@ exports[`Header handles visibility and lock changes 1`] = ` > Date: Thu, 22 Aug 2024 00:29:19 -0700 Subject: [PATCH 226/276] Adapt the newsfeed button to the updated header (#7774) (#7794) Also: * renamed a private variable with theme's menu button for consistency (cherry picked from commit ba5fe502a2fa93b91d2a1c6d31e337ea7d28610b) Signed-off-by: Miki Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../public/header_user_theme_menu.tsx | 6 +- .../newsfeed_header_nav_button.scss | 14 +++++ .../components/newsfeed_header_nav_button.tsx | 60 +++++++++++++++---- src/plugins/newsfeed/public/plugin.tsx | 9 +-- 4 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 src/plugins/newsfeed/public/components/newsfeed_header_nav_button.scss diff --git a/src/plugins/advanced_settings/public/header_user_theme_menu.tsx b/src/plugins/advanced_settings/public/header_user_theme_menu.tsx index 86a78cbcc2d2..dbad6bd5b5a6 100644 --- a/src/plugins/advanced_settings/public/header_user_theme_menu.tsx +++ b/src/plugins/advanced_settings/public/header_user_theme_menu.tsx @@ -66,7 +66,7 @@ export const HeaderUserThemeMenu = () => { : screenModeOptions[0].value ); - const legacyAppearance = !uiSettings.get('home:useNewHomePage'); + const useLegacyAppearance = !uiSettings.get('home:useNewHomePage'); const onButtonClick = () => { setPopover(!isPopoverOpen); @@ -105,7 +105,7 @@ export const HeaderUserThemeMenu = () => { setPopover(false); }; - const innerButton = legacyAppearance ? ( + const innerButton = useLegacyAppearance ? (

    {linkText}

  2. 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∾ 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 z�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�V}K%6%7hd{g;|Y$lt_7P6&` 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 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Black.ttf b/src/core/server/core_app/assets/fonts/rubik/static/Rubik-Black.ttf new file mode 100644 index 0000000000000000000000000000000000000000..055ad2205d2e347de1e62ec158ffce28e90a5e26 GIT binary patch literal 207836 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%0D=2L|xW+`B)p5C*)+SejP~cIxb}o%6V# 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 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Medium.woff2 b/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Medium.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..7db136c186200cbc6a4faf255359e95ae29c9716 GIT binary patch literal 70992 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%0AnnUv&8D$8s1tlg08y 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 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Regular.ttf b/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b8a44d2db0a18c12d7cf03c3763ef23991c3b5ab GIT binary patch literal 188504 zcmc$n2UrzH+xKU-9YE=zh{`z}nhorV9hGJ;fC^T`t{`?SvG`{W1c7PcYW{m;q{yU?9A+xd&Dy=?V;&P3%Tp#IDyByAyZtj6yWzxG)X4@>#Y>H!G5aRco9k+T@9GnTRHS31V`N=7)&z)vQq)Cg`jM)`n z%poZ;J|)?(TpEt_IA*4#_{8>`0x})ZI2@~4$=!SP?p&qRkBm)f$5_KP$vxXAchV+~ zLi*fDZ`jGRN2Mu~aL9OeHgkkBLpe!fZCDDkqoW)@GL!ZAy`Kj$X4~dP!8d8P4Zljm z41oyY%tjA))7=70>esPTZ#^>!dBE6QqV`IA_1q~!Wh2x-w41FRE5By4;T(luwGHe? zdOc?2{uc#5dDu3zZG%INNfe47McIX1RCrz~-{bguq0%~5N=iZQxom6^DKX_Hlb*Wp z_a7x@@}LuIMu*m52bq0#wn1-;O>g;r8^#u8TtZ$2)p#T^AzzMjgDE|JTy&R0&q1#IaV^cEXHYoz?I|?aL3By;7*b!F|JHdCcs^( ztc1H-K~0nk$_2QumDh0JEAJWCoHgXH`D@5uE36@Zt)f;DZe^`9+^SkNxYe~9a6>g% zL#w4Vf*Ykp!EK`@!0n)QgPWwm8d?vnC){fqW*K_vC6l!`+8f5vS8fa0{s-^ZE2hSFQR=J4lYW+~DVo;!!%o|||fOSl6o!(LhZ`LMp+7Jf7# zH@j@{bIjng7JrU9qnmQGLzZv_{v8&-ihNdD{2FHPLW|#ke5PCcHW>YuHgel9?c#RK zi^W;emsHj>x2}IQG-OJN&2&-uS?EZPR?AvhP!CXvG}dU(4XaenLRWbJEFhI+CBf)Yh_`J68Kl@&of2dR2LJ*ea>^g zq^*SVqgg0sL#02@`==8Bnum4de<_8|OGcm2h!?ZXgxZwASSo|LPd?&{CH|g+)!JQ9 z+XUE>`lOFOny4pfh7|g91X)KzN4=*yAzfQoAOUqq#LUV$MvDKfWrb<^N6&V{XdTWb zvDs`H+sJmaqwE}e#}yvN`{8Ojh0o8@r$GP9yOZN8m z9`-)=DfWvU3=S?11s#ewly!)880C=au*2cB!zG7X4u3ejbCew&9HSjuJ0?1&I4*ZQ z=y=-kp5qHAd#6CB3Ql284V_vzjdeQUld=c>+$&MD5zoi{n}c0THS&iShI zUFYX6>-yaFlbgXU+HIiQdbgc!N8HZ2 zy>R>NZsYFi?&V(Cy^MP`_d4!P+~eK*xleOn=)T5%oBILxYwlTjZ1cF~G3F_fCnQgu zJWcY%=Sj?yl4nGo$$94F*`4QR-rRYM;a}stad{Wzz2}kNql!nEN3utX$2gDa9_u~s zdpz^_m`}?Wl&^Qb>G>ArTbu6>Pg_qn&tT6G&q&XPo(Y~^J$rc$^jzq<#`Cu4frkZN6!a|Eq~MT(TMA}*74hogHOXtQ z*Artg;}GK*;}qjI<3W?1$=B4uG~2Yylx}+F?do09JIcG4_ZIJ;%)aIx=E>%n<{jn? zAI+znPkWznK0AGFd|iF>`}+H~^_}W_!1s4QXTNa2Mt&{)+WB?&TkW^iZ@*u z>4lFMk&4(AaVb)+$fzPGi@YvsF50l@s-mxo`4lT!tWU8m#SRraQ|wNlSD=4j$-v5i z?E;qv9tr#@@Jf(ZP{p9IppHSQL92t(f({3r3c3((rZg^Fa5EMYnkXWqsvS!v$M>#vQk;UvJquFl^s>~NIBPXEz0#T_kFo7<*t;= zE?=~KO!<`ZE6P7B|1nq&b_lK&+&6f6@Uh?*6?`icuTZfgqTeW%B)m0x?bFbF8+R$o0h2#yX8B!-CDx`TxLdbxS;UVKgz7IJS zav|hu$n%i*)p_*-)qSfMt6rvh*4%^D4AG_TR2 zMvodJYpkfTp~l^s1!`8V*}Ud=H8{QsLu*|ThVIRW{ z;jZDv@S@@6!)t~&2yY(VF}zp!knjoNv%;5!ZwlWNemwj_ct-f6@V60igkwbhh=7RF z5!E8^h)9a)A2BLoYQ%zwH4)n*evCL1@ms{5i02WXBW)wyBfTR7BZDJrMmC6S z9@#OnSLBe$36ZlRmql)h+!J{`@)xv8STDF<|9WfcU8`@dA6P%Qe$D#z>&Mn_ zSHFAx0rf}KPpv<%{?7WB8z>D*HK^90Zi68W4m5bs(5qo|!_^HxHVSSuw9&=Ju8mtZ zp3rz&<9UsjH9i%kMma_0kMfTy8C5wdBC2sz%cxFKy`lz3jfnYHADtXMFnVVE(b+L} zF?nMAV#>tSjAC~q4o33iQrRlz=Cz@VpdZX!srmvc2H?wQz z-ptgjXtQ$7#x%PeTP?PBY)ovM*sigCV~52~jGYy`Gcqvxb&l&1*FSD@+?=?~<^`IEHt*DYar4J5inXZQVpNMoEzY!bX<58wyOwKO z?rG)JszIwMtxmOeYF(stZ0k9#ceH-grbL_2HgnosjL#qM8y^^7F1}iPWPGFexcG$l zZt;EMm&9+4zuGoW+mdbL+b(Lmx$XOepoH=XAqlk-8YeVQXqS+f&^KX7!q|kV33C&c zC9F@_p0GdRc*41a-x6*mJa3n~U1Ymi?LM_H)_zp`lO23JOzn`-v1G?39Y1#(-sw~4 zW}SO?p4xe5=Q~~Ucd6JVw#$qzKX(>1B&vbm|NgI= zUAKJQs&}j1Evj2ew*}oY61@}4Bt|4QP3)A|D{*Y%)Wo@oOB2^7Zb{socqs8?;`ziY zmVfsWUnTJ*`y}@yb5fC{Qc2a48YjgiwN2`h)H7*-{%>Z|iKLI+1H0Gm-m&|H?wh(F z>Hb^yr`@xXwPc6nJjq_k)sovJ_e!3Syt@bM;n^d;$H*R2do1md+2dKy$~`;u?A3E* z&#S#$dKr5a>(#4QYOig$o#@m1K<`t%uk~^4Q=m`pJ`eg9@7u5M{(dF<_3M|Gk}D-| zO4*d^DUDM)ru0l1m@+bDYRbZtH7Sq!oBOxuKfC|={!a(w9#D8dg8?H3tQoLlz~KSs z1{N9EbYSYh6$8@-?i_gVZ~xv53K=wY(3$UYe;4vy*Y6g7_uF8H!4>dt(%_|oHw@lB z_~76ZgD(yKFeLAg3PairnK)#|kcC5b4LLF-W5~mywnP1gRvFrE=)j>PhE5y0eCURu zJBI!|^y9GN!`cp;G3>;!$HVgt4;$Wj`0(LVhOZfZY51cNb|Xw9%8qC}B5B0r5m!g5 zBi%<99XWL5nUR?zpNw)JWg1m~RFhFjqb7`6KI+nF_t8G1tBh_oI$?Cu=>DUB9TPLA z)tHWBx{sMVX2qE8V-AivHRj@&-^V;2^LA{mvBk%>9h*2dW$e1K2gaTp`)HicxUg|; z#&sRnciiA{)5a|vxALoh$H(0tpKE;J_=e+qj-Nh$$N0w+%o749L{8{6Veo{p6P8R^ zKjDW7Zzp<944arVapuIe6VFV%KS`NnoK$a8vq_sL?VXe{*<-TLr(pQ$D8JrshrcOD&yRJ+(n<%hax^{Zq%J z&PZLEx;yn$>b2B|Q`uDK?<1#goN;)@?U|l48_pa&bN$RKvutM>XO*4Rde;0|S7v+6 zj+wn^_WL=d=fut#JZI6IgL5vp6#<|fS@GHekXmu4<~wM<&(w9IE&*s@N``YxNgY{RlW%YIsR zbJ@$~%5sOGk6xaugt$PXl3n{ZC3VOIc4RFm3vnHy7Jj7+f@Ztm0DGERqU!Rt46Mxy=v2{ zgR3sBy1$yQc3)k1buFbPHcx~+3VQZJIJ-znz zI=^+_ughNFWc`};H#YcfXs}_@hAkToZMeAM;fB{6m5uE;rfodCsnn+Nn=Yr>q?J$W znKm?SM%vl5dz*7@uDN;I=2e?_Zho~Ta7*8|Iy6L$~aJ!SW@ zJ!SS(-4nSdW>5P)6ZdS`b9`^{y^Z${-Mebbc&L7A;@Z@0bgB1?eJoxjEg?{Y(CrpMYIOFTB|*sNn8j<-Jk%L)Gz zktb44tT=J$M8=7GC!VL;hLbnnwsPA@#Y;q=whw@?3Z#`a9$nMP;&oSAdx z{8_uR70z}%yZ-F9vxm=~I(y;l)t}Ahf4orhqIxmxV&cV&i+^0=mvUdqd#UWDs<_+a zz>bCB{#6SNuN%$$6Z-e;#{4_>Y~PjncZ=_x#QXpMGb-7@pMAQ*?S7 zEhpfz!OV&AJ-f03iCq)BGWtCOo=sa)Q2vDCzMP$4<58A|r+oBeke4^a@y>*gYI=OsJTbCAko=uSM zTl`PT`&(L-IF@)uW`j6U9=TQA9&i^Y+ zUmaWH@f_NPa6`OCUH- zCMUw6b$?JFTHC4D z4}FHSrt9`gfxXZUu|}XDFlL;4I(M_;a>9B3U*}3tt)l%m_=bN67^L(l^Va@liD(WKQEo(2WtF%rohZ2@@|9YM!JQ8_Z zY@{odh5pdb@o;u=S?iqp@8{)cKdrNRJw<+B`{`GSqK!Guv9wDMr*!~x(dmQJD=Qc~ z^Zy)EnAQAj6aGKW7Rr;oUT#dJ6*JoPHkJ&jhfBlFgiUqD;K+Ky%h^GmzM8kDo0U+VF-9lqpYZJ%COeGbtW{W8Y%aZ1;VoMVWt zw{&d1rsRwxKV9oeeRa+Wth2QDpmCowy`GNZkpA!IU>?IBU7Xrk&w=IUJGDZX1#9@X z)Tx=vA*aTmE(ix9pdu&(g1)s6aw_E13^WFHK{yBj6+syg1k5hqI~4$VfD^C-%9nkQ zW0u==$9Lcbcnt1>o8SugC8tds&pKv-ci;th4DN!P;0pK!z$T7|0M-k~9Uu*?1z0m2 z7v{`M_#I~>{Ci89iO|tN?^8?s037$mSh9mAflde~o9Do>t@CQf7S3LdO`r|IXfPDi z2BFkXRvfE3wgoLf6VMQh217w@5b9XfZ86qq{o086gR$xu>{v=ap6gglKgQgkF)GHe z7{AuFfWjS3ImfAW3|qrUU4k8vhodL31>~J2OcDU?l10?uAfj8h8 zcnEHT8{il?=vc~OH`oR?g4JNDV<~DA;V|E^n8Qqv3dVzx;1d`OQqX2<_n$cQbm#^; zfcao1NCo4;Nbm^^1}UHoz;)0e8sM7a5D994%Ag!5A#ASOpZee%I21uTU*H8ifD6cN z?Hl+t=lKqp&;OLp{)5|e`&VDmf9aFIhB*{*33l)WUcdvmfZQ&@_8-72i~)?3FW5h^ zzYlKNKXE7me1RA604^Xm;y!>^;F|pteO;mJKIWqRMSEOzTuyxPJ9n@@X@A6izZk<# zh@~~#9&5Zku5I?~!Ah_g%mui**-r-d!7YZnGbviz1-GBJ1Md;F)GEQBOREWY3b}l% z9ulj&t#!AV+6A!#IlWmlP@4+ZPtPX^Z(?z&xw;8%D7_0L#p~`Px=WN==%q}jQlx@< zKI_Qk19g8>y~GxJiL3MwC*57ByH)ga`{*@np@#(P>8t4J$5IG?u7?lR-B`U2)%DU_ zk;_->b%@pTnX17}^qrIga$ zyLu^sdMWMo+Sb)m7Si(x)bmN95dOO!-d%TRXZ3(hmMaC}R!~#mwikYKxvOs5Zn~SI zhd-lIvPY_Te=K{siub1APi8!8mD&mZ`xMSftGy7CLH?{fdiZ8N+))pop@)>Gv$BWl z?p-~$48>+Al0SPA<(#!rPZ^=7$=2Nx6v7JX>GM;1=?}d=;rdza^|OZPXPNZ$qsYx# zqlcW;^M9q+;k+KwOHcEgp60WjvzcO9q@MEw%9%y!W%W>DrR+g^nu3&`b<)qBriY~K zY5vg9YDMFa;~i1dZIwPItLj#*r@L{wTSpy$*rvL_fu6E~dK4je4g$A`Zuv91|E})O zqNglUQ{Db?x?4#P@2ld?G^w5*Qddu3Rre3o-B>-Oj^c&-;QdLYT%(8A)BU~mx|JtC z#~Y(~`%V)xNRMr^Of1~>!8mNXf^fcvkx2D<_AvJY>H{BhgyLI%lqRG!Y>i%7N zxQp)IqY!>auX#tR4?m@+nW5LMnLZku30vvmKkKfGZl46*pP{F0uBU0P`|Id#EftT*a4+5OrTeiiq5f$Ko+nAo^pMVa`bhoUNZtRPUgy@jizin|*+lm@ z()|g#U-Wg1?w>~Cyq)f!rTaVT{!x1RNxFZJ?#|FdrtAI*x_`Lt@2dN2>;Ce(yGIYX zs{1eKZnPfK41S5>jZeJM!tivgD3snFErNG@=CGFf+oLn}w@0_?Z;zhP-yZ!%e|z+I zdV7>>^!6yXrT0d;9lbZogXq0cUY_0?&dz7ExFL^dU zB}tOPFVlOY{3^XS%CFITqx?3#H_G4Rz0tD#gH&D$mQ;FsR5IZ0(btlT^cMdPN$;gB z=`g)XDy7q#q|!-xlT@xtZ<5OO=^awJ0lh;iH>7t+}A(f-(9a1?O?~wY- zG4$T3+=Si$m7CJLpK>#L>r;-Uw?5@Kdh1h;r?)=kwv1N9o?k)h_;%u7{4db!(i~~OhVoGW=~klKmNJ?}1Bz+HmSCn&S9dOhY*J!Pi*p z|8KM;&bR#rRS{PF8%#l1PN*-b{nS>fBgKvTcVxf9m;fvt{O}KqMfhmY089c4{v~^n zZp1gBvH}3<^Z!EpSMdjMY~>gD3CbtsA82ohr!+i=pN zNVn)4So8Wf+8^ipe1q-?8~6>*AS@@;w>jHOakLJQ{mGtWKL)5h2!GoSdK#eaocg^m zpz{&OoxY%-Lw2#^0e?97dOq$$7~ut~SmIk+l;+(KKy#?91y3lAf9gN$*tVvpe5fxe zUItNs#(ggk4Xo=5=3e$&9MgF0{xg_S|rf*b_E-wmYaU^o0UE(vN+450XF7A5}= zfYzFU7Ain#ZcyLs1Jpi((tZLpz#u?%qxMo>ln3$L!T~7Nhw|xc@lzZ70BTDl=md%a z8uLp)6rj9%3bM1IR6fnO5`fxv!9qQ#BUle$L$(*txa$S1?IAxwb)fMx6HuGz`t&1k zw~zv*x?TiPfZ9p(m(o(*#|iYcp6or%g4Nz+H#&!~#*tDztTrV@e$;om?WRDR1F9Qc zBU}L0XAZ~(D30mF8uBKxvR?_F;hbWW&zcn*i#W zy%BMgH=T1EP`_KtoB{u5FbR|f>7WkIDJWFW_Y(X=KowBk;wPmxP?<(h05k$^KyF}< zII5Q=&DZ)*=VYVLvo|PdS?G@})F}(~%t9Y#rvYjk#z}S@!pZ{7k*p|?064(-%5DMB zern%;O}hwb*5Evh+pMi%02mJnfdIsz9%M(|cGSl^K@Y^00_8v#fOE3zfiYk%fQ{(f z&mX{S9HTF(53Kv3>>W7njWn=z7RHM;kF09&qc8QmXs^-|{{NCzpT|hUngEoqkJ0N; z8Y9!dcK~hB*Nx3kl);Vyin9lMz$wddeJG8QngC;0pM$Wmo(JVaP`nk&gW~%Dnj2K+ zRX}U~0YLN43ZM;l`05ra1fioBgs7`dAHIH=o(I0vmD(in6YRi9u+WEhQ z)z1I7N_PHFkZlQTAO7De_51%49P^LRufvt0m|yzZQyRJo^asr?It4ld><4{8N016I z5B2>j)(icbItohZD4w_gXxv%tycYgNfX3YjKa$ z{^0*hI>tWJ+{N`M`yF@)Ft@U^z(;TmECrZ9*}IU=4Pege>2M9u@0(tu?yCT7!MB51 zND~76S-`g9_&ofSrak=eP^|Czo~SdFz}m^lo|F!G=xYtuVf|YFpOoeh&ezLD{W$8$ z-b1NxA3+O)WKc&*ldw+e{c-{d_`gk`v;5;Y&xG^ox<%on5f(ok)BOVRbvhhd+rnuL zy=vh%@cz+AXmp>I@e+jqL`xCBZ?<6JdQ!NmS>%>^-Jb?Jm_ms5vzX3;p z@%tI=|AcY*`3#Q3a31phjQW1wgzE*?%y+*c9^>zAFNC3gK4DCJ>ZqiB%tRP$`f)XQ zkFZiX7!E&yu#fwMzNKT-<3B zMZT~LtqJ-V_QY7qg=5%DpYQ9Sl|V^=dBYP0`uafm(3*g8$j~<&b4)+?no#mv;oT8W zP+8XeaIDvl^1c8_slHU^2yhQzkDx2X6Brjdzgmtd4Xtfxhn{X4Z21!Y(qNZsSX92EV|DuT^m%a?ju>#Of$qY>vPu(n&Dzf@1EJIdyc;#}?^RNvzxKfMi<&YG6e z6SXZ$wu8-eTTpw+hKSSaPHm^Pn)J{9{kvbk_o|QZKmh&QaaT)NF~nniW)%RnxuaF_ zg@uW>ZTJ%$qa4~l{;62Av$u<5YnZ-XUc)(+{(-6A3jdPte`?FWiIbWsX$rKkpmi|LGixqx1fD?r4mQ0$<7_zhooGegk`a1;tsza{8@d zq`cFYG}drROW{_m;onM|Gmg$9a;E!l?X<>ITL|m%{|mL&jg;z?vtHJ?ob{!9yRXxI zeGaQ5($IPTl>WcvVJ-VFiaC+J8_?W9Jt%*|nuf}?hUJW>vaD(TtOTdJUW+@>H~N#=$#y3 zPoO_*BmK$Z?+qOd-hs=2>`z$gO23oPuPwMXkbW}a`u_viiMrLp-UW7gjce71ya=0v z_#}WjynTed1MFnoCwxADW7O~MRweBP%KrpAzVpC2$m2a%(q6&N?`|R-{rV2qwLjx$ z3;!qB@E!X36Y5Imy}1oP>Ph}j5y*QL6m_A!&)Zl_*!sWLo%S-czah<9BsAwS`KkYN zD)|Z8Gvz%06WIf{ptye(jy;c_&+D(!=Ljboecp$<_XL)<<=ktrE2u{a0Q>V57S2H3 z0Itn^1%5M^A7p?opdY|*6S=d6K!FC3;N_!1Cg_L!(NEcDksrn^zYcl; zgmYKmVj&PZ05}3F8{>#i1D`-9z;%#c17s)6xj)aN^NWN2fX=N2=v?$2-+=P*ttkEe z@hXmg0vPvtev~K1vVPANYSHRY$`5^}*Ok(`1I!bC9#EYr59Ep8iZcENA9lJ68((45 zcrCrzjGbT}yf`mLyHowIS@4%0rO7t*mmR+P?>p&O#&19AI5%8YntmIO9|i9@GkbwD z4r&r8^t*U(fqVyQ7AR$*J_7jV%Gb6Ixs#KY^A26_7p^S`k!&pWd6QEKrU>s|b`I zp;ZOSVQ4jhOmAF-2sEl!bqgFyHmV88PN5dupkWp~py40_kewneP+MzRp!U_aKz68O zAs9-1MNr-Af%+f>&|5DA<=fCg6qMepXbk9`3OXj@0KM@*!~=>W=(p-kKvU2I(C^Uc zofph2{Tw>)JJ4L97@#c#@>3|i7XlO;DBh(dlv7ZAFO5*By=?^AJ1CV+U@qc2Aq?LM z!B@mUI}3B5?JX>TQvEuDRiKlF4baXOu#&Sb7WP8BS~vjhX5kPt5hQ^Vpu2^0&}0kO zpwxbPzJToX0i=Nbn12v_RYr$v(18L)g$@#ErJ-a~pir8@ z0wo=~SfG%7mI&m#(4_)=)r;X9DLTq@=yHKF5xPR4%z&;GXl0;eJD>$ZR}1iEF2>df zG@3VS1w1cwoj@rGT`y2hLdotx!TO7@wCHHXp_>E-2&4W08lAgYpd5#80b4Qe$iGdX zy@zfWD3_o+1X?lZ4+8lCbf>^T#@!{5k3n|}xCeBPKq&>KaRB6Bp!)>!&(Qq>`Bx~7 z44Ri+AE%b-doFSq?hJ^>vn-(TOf449OddtE%D9tfq3b<`yJoJu* z$osQi!M6QD9b3%CT$vOxCE7I2J7 znhpdrK;a?SL@3VD&y%4R*jV`K9Dw(o7{}Np@XaNBu1|n3D&h}81^D_LdMEhp1#AY?L4dzJ6?-3)gZJtfr*wejg*pq^d?=L% zmk~0V@loI6&(hr}F_T4J|65b&+;>`YtaBinW8FHJ8&dz}LSRFD{_9 zla~oNAvIojjGpnV)q5YSr7 z=@`&HkGB`lddxcrXb(v5Hxsm8^G*WVm+{U5S}*l`y)Haexhl4zgei{Z7D!K>!DO$K>H?Xmq5d~l6DKUo6x-iEdz>qC>_Us z?;|u_pkcg8mjxQ?Cs93s275|Z1RClqT@@H4=rw_cx=Ysu+6U~<&^(#rT#PXp=?D$= zmk}YW@MA2=nm~I9g?$O_HWaoav`na-K*Jc5a|yJ2P}q^s9zY!h+Eb`2a6|Yrs6PmR z{{<9lo?H(8SI`;)e6xYcVFG+dfyo$Ogwz6xF-Ax)p%`O?)Dns@Mo5%TZ-B9-q1`gZ z6(O~PVoVVd#-}{M!YC-lj{F_M-#{@&2xT~Qh(M|c9VsxlL+Kn~$O|1UkfNYt1j;bz zSTG)WMnfkGq^8ixU<$&UK~n`1*%@O_UV`vS&}Co^{B@yg!8-WkpzFa#_{oNw1QPXK znn1$(Aa4dVZhnHE6iCz;rv%bt=xKq3@hP7XNYsyK1rqfaoew0eHS#&|GyE7!@_FzJ z{OzH?f{Os-Nxme&Hli&}A!vW2AQ3^=Pr6?v=(pliP31YD7iC)5qN!*7D-0r}wfg;E@# zy$;=TDn9TRgHoIy{NeXF5v0V2mwC(F)r+8ZhD1swB6=^&uJlG0H?&v=zi0@^nzodx_Rw2OfDP)b(;$J|o731~m1 zBntQ~Xp(^TR!VmP&x9rmXrHC@5b)d3o&wr$DZK>z4z#y`_FqaL0ly3FE1-Rt(oewe zK~n^@FH`yp_=v)Eq8I^eg{s(lvfcB5d z0s(&lT_~Wvq_RlBpF$T4IE|wv0{#rTR6u)7Wto6Khmu_Y?Kc&&1>i5BD+RRoR8|T2 zE9hzg?LCz>0{$AhRzUkuWu1VYoh$1Fv>#PA2sqYVWut)hrwZ8@@ORKO0qs?l%>w=& zxmLVF5n-bI|Q_!ReliAUQgL6pna`E;{(v1PuVS?eXc@t70@0~ z*(;zuuCh-cG3b5)?Rk|00*ONpf*)}%jrT(WNroO4(Ee9BB9Ij5Q336Rm16=)g&r5s zzF0XSkThtzfcD7r43Urw&{G21FDs`7k`45XfcDPHS%G8={YfC9G0Hgs?WvWY1(F@~ zyny!B$_0Ux3;K(I_S(v?0x382qJZ|@^!$;K?4g$hwEtFq6G#rwD*`?QdQ~7fLazz< zQ0R4mA2|f#oaY;x4P>e-_&xT_B5mF&2#vH-tKrzk;sW22{i{Nvi7*B*$ z1d1_4@Oe;-8$v1y#aJQud?>~TAr*sSOb~nl6yt!90-@-8f-i)kzX>S_iasXzA}IQm zkcvammjqu7MgI{}2`KuE;7g$BCqgO-Mc)v7DU|vHNTs0E2Y@ewlHGw+8cMbX^c+DY z`vU$FN;U;_f3K1q0p0tmWIMoDLdjl0DhDMS0lo@Kb^&z1tCB4MUk#=911T6vZ3cV| zl-dcT3XHj-{|UO6azlR-bT8#KRKWT|hY9F;t=Dh?>jfPlpy#|^BL%Dvbd-Re^?JeX z1Zx9*A)wzKd7;e&N7*nXGa67X#*onlIHGQ_gAwDxi2jvfFC+TUNPU5Fj3xm4$Y`e# zwlPv$CPL9qM%X~E2}PTY)eyc28Un%)9tDjA^$@-e+7L8FcuQ!kK-vavE|9iEDGo?G zpsfYc4^Xtn*b(O@LOTJ}m!2gUlR*!JyFz<{Uht!zjJ*MDBbR}~rpA8o*MX*h{_s=z z1HeG|+e2X^<9G1m9OF=cK9Mm-jbp(SltuBWU>3qFLT3ZCRl>1xF<6Cgr$f&O3}nNz0z*OQPXdDxdJbGbKJ}p&1v18p@sdDp4806~L!OvN#w*|| z{IIq0y1-BXdP89Ff@TN|Cg@F&iTpc3Z-YDVH;3L8$Q_~g1add%eeeMJlZ_vONAT~2 zJ{CySZ-0O%cpidv$M{rW@P%To5psX%OM#pMeI<|wK;H=Hxs36x0RQ(AGrj}wQ5MFE z@dNk-KiU4Xz~B$f5*R!gGZ}ylu1Pr8ggHzoW1ubq1-3Q00*oUC_A%uV$Y_TtuYm4{ zO&%a0(iDeMzJTs^O>_?Witceuuqi?Jy(ZYygm!Bf117AsgbX{GP(MP3jZGy43T$tx z04n0#($G+WjQ%&(7SJ;cQ?ful3hfPGKN;i6G(bT68WYAhLHlCUAOY>;P2YjR2)Bn0 z5pcA}G!%?OKC7VP1+-T(O%Tvt+cZ%?_Xnm)U^4RI(DeekPcm&1(EXEXmw@hvOuGei z&t%#spnE27Ng$(aZ`6sP=VIRI3qmUkMV}Bd>f()lAvD;@8};^v{ptCcH*8PP^D}SQ zn9yKXZ(jjDQ}YfIXu;4Z5RLTbp)sHp{1>6E1@bv4)dOg-w>OmywC>PU0qr5Y(H?^K zCEnB?Kzk8yw3(p&hd1W7_YC+Qpfd%u=kT5-pnZ(@Yys_EyypmLzv8_{K>G~uG_V!< zxI%9Tw3blJUqWjEy$vvDX}{uqS3r9O?|a|@!pUY21sd87GwIO2&y2nxXg_Y21$3Wh zRs^({G^+x-Z!n|H1nvFJXahm_e`d6wp!-WR+C$KNl^M1ml%-I#ji9})8FnP-KFkce z5Oj}gb`;S4gxOg@_Y-E=f}ndWv%7%qea&baq0EJ1To826VfGRzr=bC$D8kP|%Lr&+ zY%VLHdv0?%0o@arBL#GiWo{#&`!;jDfbNIQZ3W6MXgdMjtC`yi=pN2ITtIt#^9TX$ z<;^3(DAZ>+bTk+PKl;!-7L0>`J9NB&?g`8j1hn@zlN|xwLzpoq3EKOcmkX4aP^urG zy}Ws)fSxg!R|)7|*}Pgn_W|ZL0=lO+uNBa}f_a@lSqxn-pyvwa4Fb9kHg6Qrvj_7g z0o{N5V2lx3DX1jSqM@=t3xO&E+ROT=0`~(`VWj_7_tr-;KfzX;j3kkG1D8>k(HHD55XcUirA+*L&^aY_+fnvN8 zbf4-oA7DHxzd>OOg6>UyU@xD=@Lz*25zzAtAM~LQ^&RZzvs^&;h(72ypOpxI2t|Jo z^o+!3wSbL1^*NJOV8V znpdFJg<^~mT2*L1fmRFZDbTt>^Me9NQy+@4OK6RtUIMKH)F{w;KrvPctuxeHpw)ny z1zKgOk3g#gMQ0FNTd1Evs|ocNXo-v=SO?$dVt(i^LOlsZzY*#{DEf|2FG10Vg!%-k z3e^&rtLuq5c9ze-ikj7V|@Y5*oD+eM+cVQ1mIG?uDX1361Q8J|)yc zP_sZId;18~D^Op7+8>I}BQ&xl`jk*VK?4NpZfGHaMtxFPpdN%45opxUMFr|_&|(6$ zFEmh~UV{b+)R)lW0(C#Mgh1U1Eh$jnKuZbK3}|VAdK_9tp!S276{y#tL zjmC9NfqDxXDp21;!vyM8Xt+Rq0gVu-hoO-IWW)Sw3DkGc+5+`=XdQui8CqAM-i6i^ zs7Ijn1?oL$1A%%J+EAcQf;JMU!=Q~p6vo30XtY2b2aOS^L!eCr>R@P7fjS)8OrTDO z#tPJF&^UoQ7TR2(j)Jxjs3V~*1?mWBE6^Hs7!7SBP$xp;L0g0mf+h&mq0n}qJ;J9# zI|$SX(2k%J!lytx3)Jz@E&_Enw5vd!1??tKCqolKGUiBbXb*vU2TJoFsJEfL1ZpO< zw?KUWr7;B5XHc3CK>Y*SPoUn1rU=wi(EbATJam9S{RuiypdN!#n}PZe`kg?14y8T- z>S-wT4N!lDl3jpGV}BTc?bVV{>Pw(jhmtLT8UiJI0ks;GYz@?^P#PaVr8z-%0cvF^ z*%YWWhf)P9jeY6^^tnpoj>Z8{Y0k|6i{P&bT@2R2KL@%VY=A!rx>2AeLN^Ii^nu?N zflBc^1S-Yv7N``zSD>ar4+_-HP?`fk-3lc;9*3X$KV6`_5t=u&jX*O)F~11S2ihK>?wT(Yw)5`_{}ud62g)Ece`qr3fjwR>=n{d7@&ho| z1289)A<$>wIqHo316}}XOI|425|9l)@-M0iRMe-a1`G%{G8Tj}L?{Rk!k8lz)W1Y- zU=P17V>cO)@yw?%bTL>8e;_msY=s~7$wD~<{cbk9EkGL;cl^4%f)2eS!(Te-FfEcP z4wLaLwkOBQtS7T)#aRV57+-Guo@Yz>@vX(((q8GflrCMDZRFgtqwFRJ$mQf3a+ust z9wLvIC(5bv5_yfBCa254%P;X)wLVHkrKZwfE$*he*?EofTIluCXfQe&-Hio}0mkCS z^2Tb$Fk?MqQ)8^Lxv{0OwXvhIyYV~y|D~K|Tx48j+=Tz1@`&*#;|1eY<5S}+W0uLr zl*{C4@-mrC{-zS9il$IgZBw$TziEhRoN2OYy=jwaw`rfZN&sd)cJ{x>~^7Z!{>NnPJy5Azdb$*-tw)pMv+wHg4@1WlizvF(V{C@Jg z;CIRIj^87{mws>kUHnb{<^3!Bhxpgvx9%v0M~#X0ZRfN1iTE$E@}v>RKotI zd~@l|ty$UG3Hbkb7;J80C0Iqa7&iYTdBEnoVDn?J`DJ{~(hfFvmHp+iy3Ld20rE)L ze6l=MUM8=VH_IpGXYwm0zv8P@QbLvSy3L2e<}ZwRqHc6DdKgW{LdFutU}K0e(%A4% zo3}A`GA0{`8pj$_jkAr5jjN4m#vR6E#&gDt#_Prx#y2JdZ0=$zU^3}8uVArxZ_@zN zP}6wb=DYs1xx071KW!f69Rr(>_fCb))4XqZ--gX4*xVU5&j*_an9IQCZOrY=!_7-! zb4jC$*}qTfM)@(imE{sOXR+Z`EoN2HgAh>Yz@LwsWz}Yld{Oo8jTs^ zqm)%V=m>E)rEvPmEQQ)$%naB4#SpVa4~CP0RU~6$2F}g+l<_{} zUB;`7=NV5kmQ#GjNZs8JU&os)<7LL}jLeLi85tReG7e@OxS5>cdTrkIDc5E(b{%UF zV;4RL6!xFwKUAH7XCYWzcrutMVV#!G%D=$9OsSy1;Qus!BK*RY@5--a^owFc$K)zl z`IV{wtx>knb2qHWSlQ_A`M>?pUGx8sLk+cS zy6>hnhOP&H{n1WqxPDSfI$ygFJ_+D{AfJI5Bm>%PfSqY|Ho*3VV8YPC(8{ouF`LyC zW3!vwFF!V0Y_JQk*+Jnp=e~r0%crN=Z-eod^G6va-%-lSe<+ib46UeAPLUNwex&S^ ze^)#)zMsgqDVGGzQwwi5V_)-l!zz(q!ES;TW*Vqk~ z!7|xH_LO~KA35WkYl^CsRx~AD87<#cCMeUDiOLMEj24J*?gsI^N=fCUl3y!sU|LD# zxO`kbp}kiwX~pCR1}-1t9!e>UoS)@i<@-!y5>ps``PP=@V$RIS^05M}AS=ZJaWyN! z+*vrQ%OY8A)(C%7e}FY$T^ao^-(6UL7R?^832Y1-$EL9HY%)t_Gud*skS$?L*$-?B z+s3xDx%kVaU)j&>0=t6mhaO~?*(>&pywfxR+$}PRoO9CjU8t-*hv=3&aj&7 zG&{w@*jZMeU1GJ^c~*~IWR2NX))d=^SaypwW52WJ>^5t~?y;8aE^EQ=uy*VZmcSmf zw(Jp0X75=dd&4@h=d3$>$GWlCEQ!5kz1e3rfXi$k_6G(wl-sf)+=k_5Q&~gy8*9z( zv-a$Xc1yddeb(M;Sq4eV);?%=w7c4U?XmWU_C$NA-PSU-N7_B@fz(2JDYcYdY1g$I z_&?BJ%cG<>_=@v8Ww=z);BLq(MJdCiXemZ&A~lm@rH4|S)Exge`g7@pbYJ>IdLTWP zo=A_Rr&2p98((~GFLjVQ%3PN44d~YR5_B8sgA^})l-f$4qy*`+)JZmI*QCy}jnqZz zD%;9-Qa344O5$ejgYQ{;@tV8_zHS|kuU?1n>O7Jc<%M`zUKw9c&d&?*g51Qtxi9zQ z{ycye;pOmE>U&XG(tKwVPRd^`Am0er^+Vy&T*Baj`;@kLkzJvdOuU;SH$9X!w zaD9@W;%D*Y>ofcp{u{r7{|SC8zsfiA3;aC)m0#qS_&NSFzs&dGYuQKnX?$V(8os@K zo!93#cmtln8}ggH5&xYx=C^nh&*ahkHjm+VcoTjXU+BJvZ*kw}h50VNTq?s?;7i#? zz6oFLe!%1KmF?#I5pRJnZMWoq@K*TVc5D8Wx8cw5HSg!VEq{S8dcWfB`D@;RzrnY= z-||lU9q-KF^Dg`Y@5(>&Zu}EZ9N#?!r#qK_m%KJ(h?(iIr5>B6CZ|edk>df_z20BkCfc_D9N3V zmh$j1QeHk*^5Em7e0;p*$tOtpan&fmCrJhQWXX$9k&HZ5GV!UBH~(HT^J$U~pDy|G z8Im8LDf#nR_*(dEsSuxo?}g8mitu?-Q9fTP#urF|e4!M?7fHqWVyOgQB9-JzrBZyE zRGPQLx5vBV>*Fh>a(tCkp0AdI`5LJL>&voPFZPM`VOeYtSFsColZ(hj_vWM&`yURXOe`$c!PfC#n8uG~_@%8XR1|KL zoK{|bsN7PvD9aUl#ewHjepfat%M`9i$~0xFJVC3VC2QT)+^VM9sCKG@>ZsbQ2Gv&0 zrM1*rs7|W0T0qUGdaC)g80E6EQhBYMQ7+(X>PwWJ%2MT-@`Ex@`BmAk%vCNbZ(OQUFP;0NXQ`RbLR4=VLuG&qsIIWP@Sh=eFrd&~ODAyEx?LgV6Y*HR850yvC z24%gnPMNPfQ0^=DwANazmY{Xfx@xtxI$Av~K&z+~)}nCj@2NG^s%f3Hj#_msOpDOM zwNNcyOVa9URkd1LH?6+bKx?FR(0XW{wHp72yDyKgs<`66Gxy$kAqm+NLfArxfC!lP zUS2j3$SNWNB5r7bkOUG831(r_QbeWhqM}koM8zGcQi_yPiikT!tJYF$l~T7_MQdG< zCH%f;=G^yQLj3jj>7T#kGwp64g-nlplew3Q6%GG>#sr#yXh5Kjsko$)F zrTa(sU+y2=&)t3QVrZ`_yN7UjAp+;`kIWxL1Sx821m&h2n_s2F!Q z6yCe;5*6znbGIv>yGu#;FYZG3J@-HEPIsI8o%@0NlDo+LoBNFt?os!9_kjDB+wQ*a zeye)8N8H~j+eZjriy~@4Qz01Ac{h7PWUE!{F z?{KekuXV3+uXb0uKX-3(uXKOvE_ZKpZ+CBWZ*^C>H@IuuyWLw} z_n+=p?icQ-?rZLw?(6Q0?q}}5-M#Lg++w%X9p{d9$GB&>quo(%nLEjy>`rk@+$Oi# zo$oGiXS$8;rth>cM&wavu(%tAj z<>t79++J>`JJ22AW;+9EwF_OY|4yuh{)WkDVv%280q%3HSD<@eg0^}}*wDZ=(3-1+ z3ynG$I_iW~i?12@pjZDXVxXmlT6OrMK^$z6S4F(_n&>GKpl63!hee`D63NzS`1(Pr zHC&`wdqp}l=swseuZs-POJrIjL~m=P$g)mnJCaZ1xB&CtB5|SB4!v?QbjT&vInW?Ku_i%(%(Ny$dsIVn)WE8nVx5aQv<|vs zuBeA)IMrGr8ek<{32R}VxXgM$G+IA}4RfA#2=>+3?% zimyqui-oXGmWf5ya_cHs7mLLbd{g2IaV6}Q>EfsGO8iVLhwXBy^|`pp+AdaDKM_}3 zpNMP3wPL0CxwuYTFK!Sw;)@eE<9idgidEt^SfuN)uD(O87I%uf#NA>IzD{uuzD}`L z+=uT_+%MLP2gHNoA+bR`EFKY$;;R*phxPa-Xi(DSq^Ui9z6~07J9P98e9dAfzGksY zJSTRG=fxiAY|`{EL)Vk0-wQoY+Maa!o6zxZvyR`db^l+X+y4f={sDCQ-=WX{0bTwP z^!O*x;q+CEe?eD&0X_XCbo9TWpZ^2>{4I3z_t48fKqnuCK0Xdzd;*_>5cq0_EggIl zL*a`UG0?rSGETs7Yxk6qouaVcvmGbBE zI(fa;us6w@9WH;Lj?91&IyVY*fmewNJK1*QzTwz~n|I}UvALMfTDtm=}HT+`N+AHm! z>#x4tVBZKY+0F2i-3tHYZT9W<9rkMbPWvwVZhMXW3;Q1XUVE*5pS{k$-(C;@<%961 zZLlAjZ3HwQVqy3b<$^Iogo6p#r?O)kj>|fhk?Pu+6_HXR%_HXSS_V4VS z@DlB^pR;${&)a+K7wi{lr3z2ztM+T~ApHTpj@Rusuugr`ehcf>KiTitf42AAf3e@S z|7yPnFVp+>2Uv~&omS)ahxSMCeSBhnYX8&z%>I}Cx%~y!>0iRX_iy`a`#+~K@tP|(N zll|u;I!R8llj5X0X->M6;q-Dco!;==_A&M&>`2naIj|ygol~5_&Jbs)bE-28_T+GF zQJxOl((eSEppy@;S%FjN6gkE4`i^o&SOPXMuCM)8e$^JpVSQ-C5`?auz#FoTbhcSV_O2SNmJB?tdIB^PTWt z;7dBrmCjF{WzNr><<3>k3g>F)8s}PPrSo&=I_G-l2KX&*f`{c6=T>KxbDMKJtm)Ox zoz7j(-LPzb0c-eP*rfNts=Xif?E|osAA$w`Fzn|?VLLw#`}RrLtxst?_Gwt;n_&%a z(Khn4u&aNgt>zuh?_gK|-q{6T&2Hy;_-tN)RsE9lvh#{%!$Y-}%5f;QSryfqyt;lYi`d0;~C- z+K&DlmiZxA=wHER{~8whH?Z`-gLQrw-$^ZQRkR*-05&mSZiGiev@BV54*xz<4V_d9oNO`!Ur$Oi&$gyz$zmS>y4gztwHOH z6gSmPbJN`nZ4vgSwFcH4{oMX!8^S`&fvuS9p5hL6hqy!CQ{7?iY3^`$ggeqb-OY3T zZomz?`EJN9a0}fc*sCS5Qb)sD9RsU%9IV$ex7@98E8QyhOn1C{mOH^c+nwm1!*=Ys zuwBn{r@8057q}N{`*pf|iF>L06L$tI+gWVQ*20RN!xrs4_cB<#^R@lE0PBDjtO43! zuP=lRzt~-Z6~h(U=3WMid^xQ16|lswfkjT%_;s+;Z-5o zzZ9}eeOEgCT^S^Nd7mA_(j@;9tNKEPV!?^u2O18anju;%y#D};YyZSXIwfxf_+=u4~` z{*86Xf81}}Z?Tg39;=fdux2@mwa#&@e@-Y%2_==S9OWvdd@4ruP_Zh`TYab`e1R)P zrK&WQt};|Fm8p8GEY(N#RsB?dH9%#nfhtE0Qn~6Be5Gp$)`F+1Vd^wB9R9+Q>U5Q- z{3@V=@E?X~wX2G-qAkJdZL~TAE4#639M*efSjkmj)mMde-*~L{CSYwi5v#*VYBGGD zJ>bDx318q1@aA2urjS2NoolVIcB`paIZjjOV-0#CR-zYUC3=av6zk#{SZB^s)oQk? zQMIa0%~5l)vTV@n&PFvKtIB4qsxQZyvsJaJcC}C~Qj66RwNzc9u2er&%hb=*a&?tj zp{`cfsB6_q^>cNdx?bI&ZiIjOW_63YRjpFDsoT{ZYPGr(9_zc+8ubfxkGfZ_RrjfN z>VCCeJ)j;`52+36VfBc5R6V91S5K%X)kgJ{+N6G|o>tGO&FWWbi~6Y5fIkj6oulA@H)QjpR^|E>e{_xk}+5Ustr(RcYs6VPV)m!Rq^(Xa? z`m@@v{sM3LU*Ylon|fb;0AJtV;qm(i{CXe3&-V#DegA})?_cci`%-x=Wn`+E8ke2MVLz6X!y z&F~)Yhu8A2*5BZ1d>7v21HL3*vMPv&SFvHgiUY6eYLR%krQ2N1#GQgMZ8|cgN z4f5ssPVo))4S^5lRNpY)X};mU5x$YW)8UKv`vSh8FW(pP75EC_kuUa@_(u6g`_Ax< z@s0J3^OgF_RO#%Nx`lPV()rajEzM27(&o9%O?8*~N-L{t+S}^l%4-^0YTD<|X{=iu zTVC7TR$Wt5*VLveYN~;aOG|Tgo2t|_RHX*SR)*1hl}xqLP>nk?Le1CS)R5;71Y*w& zqdVhgSGUBCkKo9&CaANFd}lGGvkWD5R$D`3ZC%`i2(lp*+= zADSB>V;VOQjGY@scj~DR)kkntgC^XgL5n$U>e;ekp09yvHgIoh(3NVMBUl(WFOuD` z2o}a)Hn*j&uBoxQskWg;HR=+n#;Dc|mOG7*LN%GfHdQZZZf$F6UQl1BnxfG13+y_y zVzX)R=1vXXY@~{7j_PhLhEq!viBO?xHB4H&$Qke#J8jg>+M>`4g51r@RJ-BY-id2F z*F`&bvv%Fh+D$iGWEd@qFzT@=+|3r5Znh+nsFs*+wp3?}T^eqdgc=R;x=MnnrEs*l zbE+v`IMq<|qOprd&TnsQYgo{@B(`B>YjtDW%*N(LvGXFgjp5svMI&1mRM*tCsFsnf zt$F^$NZyfc&8>4{7tO@~$i{}b)l^A=yuvD7S^54vzWVuU#%jLbRAzo2UyD7we8vlz zYaYY%y!-{6UdUHHFXZL>iy6PdT#HIMov(T2953Um7iWBbCBs?n0P_tn-vG-U@Z@Iv z0LvR-c>^q0faMIZd;w2Bk3RDcuzUfQE6>C8p|PU&R@v+i#ffR(~CL1*h^>n#Z14L z>6bG7QqEt>`AbdykXPTOOsACTl$Q56AJas2LtD*~M82bGa_$l3+!M;Vh03`l%DDy0xh2ZE#VR;|1;89=da}am7Kql^H*~ID$ZZU`Kvg873Z(w{8gO4it|^Q{2?BR zA?`_`Jd;1fJu$>RFqFsj$RjS4$N70C2>A{Fke~DW4gZkQ@OdFW=l2`_As(3_9+4q$ zBo?uJMNFSZT8KwfD8Tu>kr3qa2f6)%Tn|BR$B;J@dFfm~L2lm==MQ=5TyH^c_aN6_ zklR1x%|zS}f?Tg5mOJRdy*T3sxxIosa`TyQKJ(3Ix$`}_89$%p&1ZS@S+0DRGoR(l z_vG{FGyi;+FQ4TKd3c`OUOjkxSl$rR4>7+G^9eDXd`~{+7h?GfxIC;@^9z`M0n;g9 z{sl~@fcX_LokGrE$n{Xj`3pIJA?Gjl+LhCbIlb6RXZpoVznJNlGW}A{UuyD)yqUg~ z>69{^Ql?W{(W5;)6Y*V_nTRQtu|#D|sf;O=8A>5fmz1$&Wh_~_cjcNa=N2jFmMG^I zDCd?d=N2yKmZ;#8Rj?ctEJp>)QNeOlaEU6Ie+Bcc+SxgGqR-_QBkCJ1@9KoQGV*UU0bz#X7&8})mlddp)D&Hv^F$0H#yUhWLF}2T0QQZv#?@x&#qpupc>1v`Lk=Q z-Y1Qq%^9?C`N_~S}jxeRQ!LTVUj@A6z znwy$ii|?*&=!1zGO}xz`6-e+Iet23d~=S)T>D7X`T&1zDd3xfcalp9M{C@>dzXg{y8g zT=l5IRkuE_di3C`TM<`1ig4Af?XNO+1Fnp3>vJip(4)tj6Or0 z`53*1IP>8ZaFywu{wkv&o6@Qhn=x}Aa#aw^IjAtx7q%&P(=^@T^jo$QE8NG=s=QsKhajyR$=QsKh zaL#Y~jlaswR=9FKn_0|XW%M4dET7SHh_ih8Oh2FL8#~BfW%`f5%Ggo|{Z&S<;mYMS`VDcG!{|B0xt|$*2YDFZ%!-IJzOjV;RYnit z%6LW}A@1RE`AV5?X_Z^8C!yJxU);Gg3Awd(jcwJwI-Y`-BEhD_Ha!J3&=ho;o`M?n z6lBJAS-EU#mx~*G&1N35Tk4xlN_oI-)ss;hCZl$qj22)bszE^1ZKnC72hlZ?3*C8> zMsjq-Br^#eN#ux!p4KI9ar=+o#~i0?09S2k;Hot?uG-?j zRclUMwdH}U)}a0>GuPwF`OR7jbE39oarNL#&#cV=XSzj2 zn7^^8Fc&f%qwx`EI!5y&&UB0g0C_pxv^eHI&Tlk6;+$?YKjNI<*o26)9L913Jx({a zDdtX2H)}`4nVzxWFefsKZ?)68W6AQh$nag8r3-IIen6)+HTpnZ5 zVlHO>X3c^)^EYc3#F@WY!ywM|%~}TK<2ks{(=nWG#v|r(re|yz%-PJ(tU(axbh8#g zocWnG3F1u8tVux68wbYX4;GfD)KoWNZmn)=UDDWCJ-eZ%wfSUFwQBcQgp48%_|2fl zRSO;Pn?ZuBR%p2DO2w7a1Nl9c*0nT`q#tufp237LOgjo=uqk40+7>k%*I`>dEMk4z zV@`8>3*R*?WW3gf#Rjhxb8nNmt!tQD-)0b-8knGAL@c!gG_eNq%tV5#ZeUz>MdGR( z7*}19xay9BtFA~~bp_(8J0`BhrbM+(&GU5;^bHk(ZemRl=++d$+))uU9u-03nIh<0 zQv{8ui=gjxT{X4OZ_zyT4e_8G=0UfHhq)sj8jpBrJi|lZ8Xg)^^PoFZFKmqG@scx- zonv`rTrXzgf*Y6X#Y_l@bG?`Wi#YcMV*~~KWeX)sB;uxC{boQSZtB%tNOBdOrwB{A0MWSu>4K%Abxh|^xf zJ=~1GJhNN~=9%RRt_EIcS~^f@R54nN@e3;x7F4%jBc^Uno35}#9c|Ggiz+Z-HnvRa zBFQ=$Nlv2pWp!;~gk%OpP)NWko-1(;>MVw$sh*T*8U~cwiHd;{oxHqK7Th0-ozpP4 zy``=eTZy_3D$P#Rx~_HQ&&0--2Bk$+e;C*|x&dZJ^@}!vIKa*zxUD{5dnMO8^ob07UiWv=wDt?+*zUb^3VW4-Tsiu0d zsQek;yff3g(WnEwSQs3>(dp^obU3B3o-y4bH4HUVlP+YWBg~9U8(mYV>zMIPDSe{y zMD;YoIVvrx)uNzLHJlj*_6mOzl}O`dMWIKHTM{X^+oUcfO4Y^gTvI6q7F|tA1{A5I zj3~g&2sq7vBU3pE5}DbfFr#Jx$k`G-3s5|n2lo7i+SFlFy5KzcMdOrW=cMyD~E zz9*+dgz0l~Vwhw~r2S`lC5i$?h@?e9!?`oKo}y+_DB!}*!y1sH&J}8UBEhwGDm0Fu zKw)KZkLsr8HVlx4YOT_Oh1xt1*$a zUTKw6+1{dkErC4ag~XM$WLa^~+Gbe#*sj<6_HkaU)vVnE0kdWZ1k4&RfJYv*xB)gC zg2s;oxG@0(#&3jtdM$%%nGZ#o4{M6^l_uztL$%Ezd&;vk%i{oUSXkXy*Hlv%SGTwU zhF4QtLv^FcR$3f`M;+kCX=;mYfMteAPUL^!dD`M*A zFKAnWgxJRBxeYbd^f*fozHM%ar-HyuR73Wsi$=rqVAPNS-Yd;BJ3oP-@r~kYS}kaN zridFUgWM5<#%GFBnI%_Vp}7Wv1@SF)^hlYJGQo>L2|>1=@IA3iC(PmnLH}|sru1y4U?_1E=4s)RFKRbE(_dT|tK-_5)1~qk7xmB} zT6!=9W1ljS708eR1DW02Rv*U%BlyMv67U-b2%c=?b(V3U1^mW=hO1f6`gz?}XdDTF zLgQFKeltw`JO|+MO&P?^OjuY|l{g#Egk3h3mLa87W13Hh*Y6=- zzlVx~J*cwE@U-1!jA1%(h*$8TqC$7JNnH?yWgKXMkl9qh)$k2r)1`3^<71$PxCe)L zz=bePw6sN~7l*LEtgdaTZfcv@yr`~aBHA^j6GWFFjCB42bRj|-<{^b4rA@VA65hSe z-2X>Wb#k|qG*wf1QDjf+j?&4fI$yXHk@U`j{1@scC3h;5udxl!f7aHy`qx)`nYq&B z7%Hz)H0m17)DSYe#etCVIpS(uI3eS6MBGd&A>*4w+;rKH@r4IM+(kp&MMK<0L)=9} zW?u|!D|<9FEsW-Dc9cNT=#G%_5(YxXO9;5>ydmSIN1Qv6@z#T)84MxgjSYlKE3sn5 z0m;>wk1Hn$MxqMA)F#JQ;K?+Jy>xDK(uCuBCaz>llI zI8Kp|%VRdVkj{L}rWoQZzj2@f-^^1X_7jDS!xwOFbhBxOe5E~1)y{5S%r)!px2V3M zt?oSZ`Ifp18`|opHj{BzTi)E#1pUHTOoug8h}B<+)nACsg%Fz?A)bFjtgk|>HbXqW zhIoDr@%$Pxn}O&uW!YV%36J}8dH(2%5S|P?gn?ZsXaqgXehecrbUlp3ww8wKx$O(4 z;R0s_53#a>c!Cokta?J_c|AQ~3(dklowadJFFi3wNPDCVJR+0_&(Qec(sTxgYrzAX zW-FVY%{~gcGj}`l1V$ia_7%|Wjhz%S`#Xqpw_zJLWcF=<&)v=J@gmOo*g6cE zeG%~GZejNJ!I$S8c6Wx@VCN@Hkj^s%+hhDB3gFC--J>CPQ1KHbfslDR7W^2`?5ja8 zrf2r#Q684Z?2{mFthW%`>>;x!j_H8w%j}(l4i8JS-vWM2$Lwz*&gC+D-@xbkW%q7~ z-M=BTZ-Md{ba=>vw?`SJZ7&S_*}2%83&|uzcBlEh_jq#UkdVh^m&>x&lUjAc)Z0C zGJErwc36J1H;;0gd<8sh7jS74WoP!0lVW^;N*- zDF_z#Xr12xBNBcVEHV~`BX(9We!n(76f z96j-PLS35|OEa;m=9c->7Bw@0%-Xtz4K;P;rbJcPPU3`Kof0NDc~p9Lf={EZsBUva zSftEtY@V$Z%Q;x)>MgYt_!cJ5Ij63+p?yB*PST)hb&J~=kZAz07}030tymIrLcfy| zw7try33W|aJ-003XwSOn3Q2?Rt2?g_4mmuw;FUBHtE>4{b#=9zC4Fv7bNhm>Sh^ns zi;DWxH@7q_MRip-POF~X-dIgbR?g|xH@COeX-q#Wv>?yOL7t(4JRP$bb}eo~Ykk9Eg(mYT!y}n(5oh0l} zehA)5;4PI-J1aWbbH?jx%IXB_M69PyLN#i{WG@!p*GZ3tbOVi+I!WWQ$Bt?c0kv}E}4y3 z+I_4!^wRjoog6J3c2~Tuv`+041;#icae768qA6rW!6UaiOHL$?Er&3l=-h_C@km8? zIQB}>o{{!WkpyNW({=%mWPNL@o^Hbf&GhRi4>*m$uE2C}SegWAD%w`))fpQ0m-qJI zCv8+{IwwIhy5KYUu!voEH@a43Aenb*0h26|BMdQx-r z{?U~FUW#|^T)ih%K-Y!~S3uWWOih%hu#=typeVzjMg0<9QQZ9YRx({^ZzUn>9uH@b?UNVe zx6gw79$}E*;tBBEcL9DYFTiir1^9ubAa9ig^9p<| zWA&0`1H!XLa~aY@zePL}Z`kUmP>@}3Y4r3SUN##X;dgv>G*%bO+?tnq^;1pJZyf8y zM57mI6UZPNUW6R0-%{4l9`r7`W923{-cl7+6Q{|hnk6lbvI+CwWfCvL zw>4RVmo_xj%ciAEmMoD?a-tPmT6K1|Oe>vUnJo^KmrlzT8_TESck$V!)3ZgzIg=-5 zizJ*hkZrv;b@Dmc)??FvW3}PM{A`@XY~j3kd`$p+B~Bc6a2`)0P8m+dsY%_O`J~TS z8gNpcp8rFh`2QhK-2ad#_J7FJ zW3G}HVB&5Q*U(fVmeDd$ES`fWd_)tSaUtsUFYSpnic9tH1^Rc2{+*zIEA;Oe{ad7e z17w7X;mx>+!C0s_iT-r*fXJlB21E*UhF`?vHy{*#gH{KA^R2`94Ow5|x4`-ozlGKT z{1#d7(t6u^yA>~gSo_*Q(|Va6p~Y$9)bso4-vs@OFJb7hfL}2U_Yx;so~y5CEBZPN}MT%?`(i#qW+~?78qOfi_`w`i<8{(Yib?e z0Kk2^{_UfG>FWW4$0wapZ{s{OI`4|0I1UTHN%)AzMcj_lHLtLKW?hZ*(r(nJmEVCg zxbDU|TWfJ<`FfnBwgG30KZeuGp28WV&)__>tvE;gw>TMW7iw=0P722vs5l>dAI@Zd z(|Q}{g73#^I&?bw-*JxTM>xUzGn@hbCC>f+56=Jo!8&Rk$64*RaD`9ABZVKQl@{WBQmQwUO`Jb**jdi_J>#z&KV^LG_@pxrpZWBe58}V}%(64H&y25n zr)pf)aQw&Oe|Y6ygzGAsDyQL^SD8_9UB$fe{pCB$pT>Xxa)+*E%gdU|pDz8ZbU%Jq zmbR7VlqQW^Kkjx)8{0AVtFZ_1KV$5av1Mb+#_SohwfyNZBgbTqJ$S~NGj14LHhRbC zb)#2}P8)S()aRqdk1828eAMugc_o*YOe&dFyu0|Zl1W8Vizels716^s1aUa(3o4 z=1k4827Wy7(t%~!UuD0aeN%P|zTctnJ(YX#^^cML-|N4-|APJ(^mqDw)^AO}W&MWt zOX<6-?<0N3_bur=ywAIRUhcE7&!v50vyS<9W<8O$Dr-zuZtpjH@5vk1dwlPaneS!3 znz=Z0Ugo8}I(mK8>tL_OUekNUWE{#^oH6h8b?INHzm5M{=~Zcm(%wrwnEH0=i#n`J z9F~}n@M*#u3EL9ZC)|+GmM|k>d_qajLp|TXUf|4N*!)r8Z)(v-qEV>587TLDgl%fden7sGkbZ{qyD z#W*i;ypx7=5)b0s#Vt73ahhF%vo-gP-y=6-B+_V%LC;OF96H~R&b0!>q4Ngm6s{76TzpaC6^v1omU?DF_175DB{!F}Z+F!T43O+`zp_I}?aeIn|^H zz$3iTE;zr9Ae7^ZE-5%4O{ZM1?hdC=-G&eoIJwNDBSyT9bBrUg7x6`gNNgMCd@p8d za;e%1h;(vPP?tkl%W&f51e_V2i*o3e9jAmsI;rlE>0o+P7kHLuVU`dNTuEU=I6aiR8_?2{mXM}S8 z)1cSQn9N@bowQu%Dj-Ut$rAZDFzt|rj00pbQZChU3F^uD^@!&gEaXMc4<+Gbz^?QK z&Kwu{_|}W29|Ser<$s3Q*BTPgvL66!KjMT(HTXH=FXKwzbBWZ=w zo}oYdCgi%Ea*ES6z2(4JiuhWlkM!a55T`jNOh5D~W~r0uSD<8XGyM^UerPvx1t_N& zuIXn3=V`=8GyUO+uSYxyar)xQN&!0w=cMzYtI0D>N};3(jc_itThdqWCTGL%{4e8hsPz5dKm9Itn%nu;+0O;WJUN z48UH%$%I>?U|0{i!j($*dqZ#3A>i$XzMwKN5BUyejz*k$_y_gNDCjOg=XcF7p8)hS zoRGLzZPGP35Z@j-i1VGV!#UKmaK?2$&d-j)+1&5ryzi|zL;Mz;RXzvjsE@%J?^*aV z$~XAl%3hq7x&dF6S%wqZr{nx}(^D|gM2$rA#ymb}Y& zr)XMjfb25C!wY>QW&yIX6W&BXFiI$RcqP+lhA3Ip2`?8AXoLWbPE+4PpvFor1?-&& z45L((OaqKY0pr0Q7A2SyOG*ML51@lc>f&!;JBt#~4Xn}79FiN~I}#=6#U(L;6%pJ} z3G8uE{55bJqi|ON_9-ZR8n_^WTYQ&=(OeALfpJl|0mO%KiHN_}+<{D7(-@1iVHTYX z3_T&N1UmCrpZ)m^&ivekzD}om(s`b*t3T@eDd18I?zQ+up)jK&2c;BGFu_mX#iDqL z4zjq!zsX1dY?Kk-9hi#~;K$) zJrIV48PMS7AcndIq#trg)X*iEIGg1@oSjVZ^W?=Gr}>idqHf6sq;DM|CQ;%^S~3Za z+J?f3-VrOU5AFppFc;JL`k-~8yb!sX<&BmtpOl*|l3H|=ryP0QaGr}ekE8Pp#7XzR z#rH8H5(YzaYoZ>nz7U)^)BP)&ktcIMenO^;8svO95@g zDYvhx%@HWgBLf2g$&MKek6yd!0w{eF2V>qAwN_rMA{SpY z>A>23A7-H^@a3_U@EhnpIBXl_HGPnNU95&aA{jAL==363MZ?T22CYgp9~uvcu_!%A z9w3;Nk=ToIh5<5LLl|e+6iXHj<{2p&DU#}fWyrT={;}k78b8Uv^4~-IX6NIJc^uzs z*~60Z_b2y_rds%hB@5p;^@xV015*r&MNh*_d+Ns;md3ePgTv}m-;ChpPl2vn4!oV6 z@a6z-&Z$pC@J_!6cvFFQS0}s)z?*QYna4HXAY{ld03PZK^+0@uL@gEOaj#F+5Y$qB zY$ph6Dfo3K2qX)B-U)))qyUq3*!Lz$O9qK43XfuoA%D0W2X3HW1?wBDcohO6;bDR+_0z-j2D+;#=@d;dWB&)#Jh{O;;d0bH0 zd^7?(%@b*QcA&2j;9CUx?Cz&P3LmIqF&P!Q!L?s%#!}c@C$LU9t9?) z_-`>`@Ls?vjvjy@{mTaL07Po+803I{fkprw=zVqV|oAgKw z>l(BEci>~3g0B&pnj{MZEy?AJ17(5lYCK{j(9m7sRN^bK3b@Cz$nuA;m1+p}jrEI1 zp$G0V5qg5Y`4(l=cO`%9iygqXb=o7EBE}ci$R0&1F=?dkDR%p15G@@vD>XMu?A40I zHxQ*$Zy#rSVLaC2VJ{GTts-dpw9=BGj)O_MKH=B^ErEQ-GPnsn>M+)Fx}|W&yui1T zM1W?)2q)B+eaxAwWjJJi$s9ZRodQoIwSw|sJ&M}w_c`tZ%#k2S2!I!49L&5j00A$( zh9il-M5=@AD=f>o-Y1^~}8G)=4*Z}ypGrsPCxNRRKEvF@N@#U(C zuzYerQS&<`7sfM29Wv4$6)w4NTH+MyZw8|EQSL5HnJSs2_zy`>eKMEpK*K$bhRR+` z=H4`v^8p(z>)(hkkD7kLwbkC2S``8(w_V414 z&3zS^2uS%>Q~Vh5ZJLIKRk`U;kD#270y4}ySBZkZ+FYo``KxpD(0^sizp&4cD+`v>QIP?Gj1u$fGMZp8l2M65=_ zp1wifSt8r?p|3PQjFxP#4}FE)0&;@OY0ylA_9AT$xF9}gE5Z)Mx9B*e8nn@p*&DJq zaQa$65VBVz9ao0?NrB~u{?c=f#wc3E3ao8i@WF(3#zwNbo8-&y#Q zF128n9@!UThyqeR(ez^wFX5aYGyS2K>^rpYP(UF;U+6&&UFyyL)+sk-ak9GO)#rdE z2ErZ!oezmp2I_I3r&|aDdVO}ll6q(0JBC*ul%B%C7b#5#%xoD6sIPDFy{2x;)8|U` z_E{SDpypA8I9rYQLZab;b!Gq2{YNto)PEm@{==hq2+Smd!yGY_gnQkO%_Ikio1O!_ znS}i7!gUQ#>;F2FI1yjG?t%7Ery98>zLK5OT`4n0qV|Sr`TjQiYF?OIvWY6S2SIR`zRr>Z zz8*m936cgDAB6!287tD;k2=#euP+?hgFdM@reA8!-I9Veegm?wOYx#iX zfD$j*H53LcV5~4NX9kz+qwdR<_8D@uXv%*kN@))wK8vXk1iaE-1g}X0sQ(ZKW-JN= z#xPcx7ustUm&?qPT}D|NY~DU*-v5)PRDifQ?-PW0O}Av9NBTU%ye0sG(C4nMyquqK zxeoqFxiJ6s9j(jt7V%02-@e0`3PHdt^$T<#OS3=Sb~R zuGB{`uYIO@X%AlN48->{6@n126_|Bj?ENC{NgC8Rh2C2kE4mJ~ZwY-KTa8HV%B#c@ zagOHoI#Ejb+7hwUCgm`6GGWJ010o)TWWkT#5l%@mQMQWWZ0U^7{Sc_eFm~gO1BSYti?`AoRaXqeUsl1msweN!BvSh#o;9 zvxTVX;I;1^EaT1H*ZCl{eu~k0FA$}iEr@$sk079z^S&ihhNiIA%h?AALJEzU&b)3m zyzGB<&npL|=#6qA-}9OmbWQK+OobrCs|90ZeDCqNCuwGz(7TASbo-`k$KJJ6_jcF5 zIRVgwo&-Mmw#2{>5x<9Xv$rb;TC?|cy{|Jo26g}o0d`8HJR)lvzBfi=ubXvC7UmQR zNc}zW=>0C@-n_EYlp`zCl3AGpsg6jB7-N&cE~7a3^gaw34&zs+_x=CF;-+;UXL#TVh$j$ zBbRxhUadu~)w0pz85ldryPc@@br44+48dLY6P8RrgmnQy6?;*PuN67cK_UAFedRjH zUJCr3>AaJXJrC&!>6>(ZqJdh=d=n$ev;*1O6Qb9TncI<$0Q_wvQzrUx=3|`uSwQUU zoXpvoG;YxI5QwkLoRm2pu@yS7B$-%cW-h?5uBpsfNHc+?Fp|iWahN3!JLhU?eAq2) zf;^o@dgd@_szW-*uSuR>I}m@5<oGtM z0`iE4fPXKna?)0(nb9wL?E(ZL?HZ=7Ybvc#yr^aCiSIuifCp_mo-$j5FXoxHtbo@c z8$3ZRt;z)4|BB>HS&Mi+)7s29IhLK4lk#a=4&WwN5@bk9A#Fu@9zhe@ATuDxo2NsA@qBZu{5s~?9|!cIp=Uct%nBaJi4M{|=$a)j*`L8rL)Iip5OC}shIH2Pq3q6=Z!W*0`!u?9-uEN}@6{7r+ zS&PAWy5|0X=8hUc-!T10L&(Ote=jYb3A`SOW=1;hyl>7P5~x z^lX>JcbgCKSUt%nnS>F5$CoMJ{Ul3LJ#^h6mW3clOWJ@n!+ZGEZQpk|aX1 z2I)KclKo2*+Dw4|!qAPD2Qv=I)BXIEG#VP))XRNDDe*nTy?P-C@q(SvyP!AK3-LlL zQRqE5ikC?IioJi`*fNRxK^Fn|_i7$!i$rgByT|ZI++xYZEqYvl2YD43IQ91Pq1LGYrPu*-TT@g}2zk#d)&Fa^5w8_rD-;!$r&JUM$1_rwEj zM4^`_Nx1#=^OIDbSJbd>d1XVU3N6=aqLe^oqtQ!}5(IY%7{gXJ{xz=zj9&^~4+dSY zR3c#?_6NHuQNniQK>&r@HJ4?GKSs0>ZeuQYVXWSja2Iod-c2yUV1-Mh9(En%BTMi# z=5>;nCq7~=lt|JO!-gY`UkY)i4h5)(%LV_^_^8+n>|L2s zp2Qim2Iach;~e%>qfN1W(;DFn?%AC=himk-C|)<{oh+&Yj2Z0j^wFGM_y?zgb}sUm zvOwR!9-gCf-k`Y;#r;$cmUTT~^vp>bAf89$I@}A9$`o>O&DH<9owau?1$k2NPy7X* z;}6$J=3?xvMPl>tMgi4`3orh}Xt^?{!D^j`U&38Ua@n__caJjxuxm*!d#Sw?kl~t- zg=aiar;A#vA#qb0&C5`v9+S zPihl|I#enZnh<%Hk|fqHjEb*eQ?1jmB_s*#uZ@7*!1M`*a=NeL3CUMe7s8s=_26y; zY#Y|P+fr*8Q@4q`E^6P`ldFp5GG4cn`mhV@(QS&MK5Jn|j^sigcA;Hj#%S0=Etl@Y zF`gy05Glg`mZcjG>4wK7#U!zGS;(ISs#(5{DCx{THc5&=t;84jjb-?I~ zouhLJNI)g|0>9Ls$R42G(qrm=?Xj?FS1{b7T}FTM0jzrtCBLonwh;Yf^s}^gaW#?? z45L38y)D_(@hzGk?;9qs!&+)%^6kmD8~KtkUm?h}dy9sF5Hc132(O`!euLwL_F(8{pXm{2Lr9D}pIC(g}y8M43~= zF|&4@Vjl)X+6U~9SpJ(ZyUyt>zk>e>;Rc%H2r(l9(bK@fW=Y^Ypnn)ZCx_)Hni{C z_$6AGP{~O9&@<^20GqB$rnQgo=1^Lz372bK+-^DIcKlw1;K88j#WF#CnjqR56_`0h zBYsJ4$IRViJBSU6PLyX}A{w&r-r??Kug{cj}S4A^GiY{oyO zQ}9-;-#IkrLDuk-2Q+dgK_?7`v_|@=kYp-GH08VyFo8Emg&2eDEDeK&1?s!-FJMC& z4jN{UvoS^lMk+$MkE2XBLb#8^qbLw0f>%G!X}Ws6;%%9vCSM&v}UHHuz>pU&1v8I=?tTcXv{hh|n#XV*!gj%HP@?#v?2vb=) zNi#lCk+bEcz%BxIQKWPz*MG6bZ8P_q(rw0bbzX}IYXjCRR5~A?FIFmaxR|oh>|<*+z;O#w%)CkUCwzxMdmXr~!9Q^!sI-Rr_9M1}gJqossBQJNGJLxM zGjj&vQhSiT5zeVPA22}kJ={;htVZ)DrBUk&JgcJ1>)Q@b!$|aG`qyLHhaQe#Yx^~g z^JM8fAK{l<$G1%UiTl%H^rkL*hop-s0J{p5NTUkhRGrtdDw#9(C4A$AnazbjTl?~K z;NIfHO5B$%+mOph3O~Lt$;Vc_*6@%8SCWXOQt$EH?n7;#B$YyKQ2=&1NhMHMc!SI2 zFEd;eY9C<>pj1yAfN_fsIxfhnS*8O^1+5Fsi(j3tW+2UkXsITmkI~puutH~`Mxyqo zwD!)|GL0jS?$@A@!!nI!nNV_-WMvy3=a-^cR8E!OA^@dXWp#WABe&BxACqw{*eaS&NVtn z=NjBa$?GhDUZSQr$wJ3-GSZo@pO&%kzAn+gC~&GwK#qKp&%r++0j5bBpSbr2_x|*c z80C!DK|1lci*T2s12rhsty+RE9z**8M)|wCcKk%cz8&FZ&P@=|v3Ec}Z-uW!bFnu9 zLgA5U9unRfwF16yDrHw5&<^$j&Es^<13lTE!MO=SJfP$4iS|U?lN4nfJUd+53j&$~ zjRZSEa~e)`~3 z3W5A0RyZ0;7P{1ysIa~PJ}YH50fS) z9184bQMaQ{lC*jy9^M7&>J36KK;LN8c?W2!WEWBoxF`%`Z;(~NJO&^I?-bK7I2h^j za2*z9yY@$Ff6%5kDo84U-4?>9H!%e)i-@eK7yBNJTGT7vg18r@G^HS42U$+BNOABa zlEkw^RQGvKK@`pez{uWm(0io)&!`m4_nh*gPNDW9>pE6TOmpim$Q=if;($4aD1Z zpTa}vIIg4M7>I!u?&I`z`Z<0l-~^p~XD@sr->L7_VfBMLqK>L#>bUAqCw!Jq_|kp3 zzQIva;nV`W#eT1SpS{k$-(GJ&U_WR-WN)w^wy_FEpHHN>;r071R35Kw6?6{b&ec&Z zMs1n5wV&MthX~jFw!9GifqJy`9?MLxm=HvDg_LKHT`zd>q{Y(34 zN5B^NyYmdF*e6rb# zNtVgMI7c8sO1#_ojrd%ADE5k7Vw>0??hy-c&Qh#(1as#h>qFRSn<3#ajFqF9?z($- z=>U8V|G@iYpI{gI3mb0@b?N;%WIH)KQCjV_bUskSaGpsJV^(4uC0psvIHy##sb%VC z>Q?M|+@{}0+o+z>?~^~Ro>80eZrT>SSH9J9=zJBNwsHmZ#Uh;BB3&1IC_ZPbb0zjJ z?^XAyhj5ZjvU8?$95eJU)IIt=wwLiH+pBn^m)=L;hd0vSz&q*L&P7hGgLitNcdmjJ zbG2HjZcsO>Th#4pwYp2KQES!x>OuG$x8oh$9eB%kC*JAZrJhr}^}FpaSZPj`bCxsF zIfu^gan5&UIUDeB>ry(&N8wZ!^{{#z@5yb$n{tlxjI$a2>oKbb+VP;%0iXC{b&a}K z-Kiec*5uvl4!rL>%&B&k=<`kDF!v0_lX7P`W1Mn&Q{I`cZc^)ko96UZKgBiG$;9)! z(n-Odkc}CumvadyNc6ZQXS6d9bt2IJ64AG(W9Om)J?FUH;moyq+OOlyp^Ke5XO2_v zv^w+-;6nWt;5xjid(Lo;1m_uD=+vm2(R+Wu$wt$hnYcUbOm=2C&6xMU zcP8Q8!vEk&A`-knP?d|p+dmrvMpfCRhW9SdKe+WH$ z8%ES#+&_qZ{w&7VYq);^y?!f3+pD-=k1_CTjJ;QIe?LaV7L3G~ala1Z<5w7$FX8?^ zjF!z9rFc#ZdhT9~o@X#>U(hpSI(}0H{6N-LdVA9wt)kv~2JaL@zhIst4MV!(TFiQ} z^tL&4O(wKWn&?UTLnMfFdM_St(T|m-^8b@_2kf;tnW~$4ko2E@qKnSE&UKulcpiYx zIBLg9NN=h?sdv;{YEf7hcCQJgm4`Z~T2IuTkTPg((iP;lxCH+$^zu)j56I_5&mJy= zc3O%59?e*ze=5$3^I2(H zAEu+7%B>7Kk-_Sv&pXJ}=N}B99%B6r{bP@H6}0rn){XY3_NUfOc8A?z-3%?=&$oDf; zw$`f$FfToz_dOnjolK6^$2u(y0r=VJ=glBZ!okx`4=2(%8513EUdk4)WT4# z{H*f^CJ#I%d0?_gQ-g8_<1{antc1r4i#tEmNJ>c}L#JG&CGcFi%LG_S}>lP2~-+w3t_r)LHtaoP|c~CkTSy>s6 zsmjTtCdb98KB;{MC6zXeZfHyF_>NEqoJN}UR0#QVw;IyLT2|>mdyoirY8mhhxL*qNbP+z|= z6r94i?}VXPoO@7TpD+|v>p?NwdfXBXv?D~aGt}pk0``fA?VAzC?ioen`!F;ComZZK z&&2sX%AZKKjV}K{-@w#?={leuO&Xb`RvS&Tf}*nJayx= zv)aqfxow8Hy8iOv9lo^unewIfnvSyh9qxiP(}%d#11GPnyZDL;iSd;;k|p!A6aRFY z-9>cPWoaOzmk$EuD3zX;kpbR?y%hRct_D?`m(}+1_?%;qBPG{t zVOoN%D>Ne`#a=V<$~(?{aKnT~Toy;;wvrn4ttSeeeAJaEXsWTj;5L;t>J=0mSH z|9tbg4P$S-;Ov{4OV4{~@%XFG==gWKc;hE;_F5-KAKENpH(zwlg!!Y2O0M3&{-q=B zIoV>vs^bd+Ra9=xQP(GUqV?iS!caZq8EEWi4L!bxq(cccRDFF$7+3ddgR9P<(Mr9d zhiUI>XbVgb_zfo8mmWX-)KfC%DS7kpR=4{2c3E}gei{P~@Hc9FtQbpy@8xmPYn`}F z$G_XONyduFM=zpDoOADx6$h`q7NyYKw7j$zpnRC2A;UgQTnD+&nI0EHzYEz1JNAjd zvCl=IW1m}nL@AY{XY=J>?5ul?oRj$Z4J zfBf>xPD=5uC#;umNxSaAo%W=oJ8!+!DO+`{SNs0Wi&Fj%XYTc&n8XHm zc;A`XT^2O?zxO`*=}!*#o;h>o%;_^16!EdS^!DKt3H!pKoZA8_?2CAo$*F(}`y!rY zaw?$0z6dCjQvo&Rwn1QER!2aE)e+A!t0SPo>U>DS0WPNu3OTJ`%XOJ}n%NieG_xA-kwQ= z9p2t08?l`X94d*g4y&kPb!M^^zl9aw0L(Jm8Bq`rGnj7J?zHOa7LxT9+f3sQR+~1$j{o03H;sqnMOwNZT4IxxG57c1SsUD~dp*Rere^v+87(XN7$_&f__bRLU>E;mT056?W zP!=d18Ks=7kruTlpDZ8;6YDYrIRy0xBNYUn$(WCst=vx<1|J}bSj*;Y zzma|rVeB{y+L>sY8}Iss{6<=}*rhsc8CSA5R0#n^-d5!gmrHMA2ZB#x4>6C(hx4PE z+yG_TT|iqZ911RBck7|pz08i$Nqo<@H9{T8r$JC$oZ%11P3V$-44L0!xb1M~p+40+ z#y6&sPIBs;WZr4y=&a?NHHC)Onz(Dr~_wRh8c^SnzFS)i(=HY^tf*v~_>YCh73U^xW|`iPzmv$ncX# z>G@9)ruCo?=x_M%YhuIZ&&S|06(D%Uy+;n^yIVlT?iSCo-7TPEcZ+A)?iNt7yT!9? z9}B41#{#-o4{bh0PXo6?;#ur&?4@b-Jyc=F{(SbZ|L~Md%?)^9XQ@FXqH%C@BW@Zn zf*TZ56L@pdY1Ny2*Cp0$9A2nSVGJ>3&_@n5 zqIT!B9~^3mhL_sGg;=CI33a{AO3F?J6t6=SJW9>S#nlAJ5 z;LKX!Z*v>?ll*VCda#O?x+~;y;BLlYuvClORJsVwXl> zm$u;hROjouy1Ky(z&V3;8mN+Yj$a>n`FvFA#8Y{Xw;rh>GoBJF`R%w=H|3a1M#`>> zlPOV0eFSXxfNc`6wKlTEtjwJUs+fPw@euAgvk;18eDH#p=loWF=@7~J-^1y}D^EE zdShG4_Wva&eFKSKc&zMj&6XYeYqm&-*Z+NLh*@w(OknK#QHO~~gXFg-w)B7WSFPk@ z?CY4za?GU-p9>osDqG7DjV=;UIfrkaPBwo`b5GTf=z5|#wRz{2E2VqoFXwETWvOhF z#wc&9qux80l|+q}G8y4mxr|ISkP!i8x<^1;ayxY$x(5{Kp}2krc4`tNX8?EtlfXFA zV5S&v?H!;CMQCamH&|LrssW3?+O_GQNpk{ErH)@8F(`9!?&XAqS2K!kPn;ceVDhNc zQQn&~;!Y-#)Ws*~OdX#*VvO5@Nh2ah+V+eoO_;ND%Glrq!-w___ZvDfz@h6ju17f~ zd@d1UF74P11(eN2KwGxtP{a?QS`TgaqTyMlF~qYi#IxKoH9V_&!RB33|2JaD3{<}O zelf>g3|zPxwC^B$2N%MFC1w@|xk`S8f5y|Y&%RH%xN6jr-Yzy{2d`Lv_fs-wnqR++S(z`i1QakM{;1z#| zd-GA8gDrU!9tvJzJa9!o+i|{zf-8nl6>I?aT2x&@oA6q=IM_2|*q+6TE+(q33vR9{ zydHn3Bs-@BR&?5$JBw59W3-*}go(2>l_Vdg&c~?p=}W4uFL&UV;3GUURVDt3+Px3l6#Ne^ z3iDDbZ+*9Y$D@liCHwAf+sC{URomJ>;Za1Yq*|)tu{3{|^KYR6{{)nAN<+uO!Mr z8#k_1d6zQpnLo>ENEI~jC{{q3J`vECc5E~b<*}H6;@5zR?1deEXafuyjVUV03||JYK?M~ID#kO7Wgb`_c8-b4*{Cb(GDb1& zd9KERZ$c7`(1C}x<^;(b6J&A_+sdbVJNELOZRvhs&h``Zae3C_K?UO+qYjL| zbcv1*DeSkorYPozVME$1Ztmwla@5h1JvEaTPVZ=y*2DVbHYIIXJZ^xR>!FGPw2vNI+W=MnsE0mnfEu&;3cSx7pz13+s0K}&j0S4WxS)ly ze88ppM|#@k>z+2I4LFcQ)nTrG3~#RfZ*cMqIN2953f9PHAe=eo5$Q8t_W#CLOIKGS zxXPY|kAw`ZjlI1bb8N3l`Jqj0?9lLmAs(3%V@uqIWz1Sr@!)pE^hqueKK(|l@lIN1 z)isMgAHQzi*byUU4rtki#Dq_2O_s@HRL=C*$8HX9RrRt@avBmD{l=uDC3_D~oF9c% z=-Oj?=-5c*0Y3IVcluP9Wb)ajcPpyF2{8-48tcSrm@p~1in;YvKR}+mD`uw88^d%v zXlzZ~%%G^5;|01+EG)=^A)BVGtqGm+PVULMtxBqX&nz4~f9&L}KD|=q(%`V%XZv=% zD9lVyUowBW>BjB+lT+UCR-SqVvAuQ@<1_~kyFeCoi9&n(#_j-1tVsLD^|aXQGqSjZX^R3}b7|aU1u-s+EYD zP5wgUT!4K16LcXVR(JLyyMUBI&;3&usH_3pDw{lNU?&^6;j@}KS5{-S7@ zXUh*i$$fk3Y;UQJH#WUwlntKsGHz*PV+2d#1My)ozona{#=?|kLf~EL2gUC+1U`m7 z9SeCQVY>$=`Poh0=(#3l#nGz8ch{}_X!)Y|7R=t}-X(X&R&q?1op(kBt_<0+d~Ky_ z*8UE*Z8FWAY)U7uT22?!udAMCCw;!H^z-F`!_#i~?^Yh$dUqWY7F4$Mt<#?}o{a%@ z*VPYH_C{qNFnuQD10gdJ`>X{#5ByQXGqwla$llnv*!`b;`gI#UP4|;YRi*8QlugQi zld&sejmsYyg+mg6X`)p3d!MYP+Hj8>1& zA3HX~Z%ojcnPvAEEc~z_>--!^q7jR>wUq4SLUMaq`N;lG^M?$_6776mnEK<+&Q7M} z(~6q?2f+b88sAadgxr}kz6dDOZvv_qK$(6M(7M+`Ya5_k>xpNdHb9MA=rKGqfHGYu zo_*c`<+_kVH7xxr8*PKf!nk9Os+$}3p*hcGG9GDkcEOeWUrdv&=fv6%@apDfXKL;4 zurNL1D1GbyU}M*=eM16l`#Nhh*~ZNlh6OGTBUk>Nu}oXw47qANWT*pHQD0>+H;0ji z-)iduIc@HQ!OkehJTt__l_Kpc`LebGoJE3{m(&2jVAy+HRe4EjzPrIQs6~~{pb?wH zr%a7}Gu0))rbAbcv1eoVN6{CLt1gCZ?!R(za!Ek$?00il4|Sh1G4||=tcnyGnYMJr zs>DT$RBN}Jx9FV}F?aXW7A@KhwzeM_ylPx|h2PpZ&rk=4(e9&ymxMUauSbi+Lpqq$&nuM6T4KY?<#MHh3#Fh$kL1H zlUzf4D@6Ss(_Ic)JZfG|VJg7c?REI1_h=10vAe1uR)BtbNV#tpt_pP9XaM% z80}BUi^jMGJUIwD&+qdbGtpH(v3SxKq*vX~#E)Jg(*}@@z|`=z{w2mkF)s6P-V_>uXX^x%t&e~z22i#>0$SSu<$GN~ zpEf}GUKh}322i%w1@yVhc6Ah;EZ1W07RdMYV>GjLfPRU%{U$MX@$++W8!9)m*fV0E-~+Z$sxSUKr*0|%MMCFWF*-$_R2FsEghQ)}Fi%x9#+j94we z#c(F_vhDQF-7Z@n=g=T>VX!a0nKpbl=q)(%+qxdzRu-!qljJJU89G99W2%=bTrIBh5Xj3!E11>_CvQzb^-6iucfb6zF zW~-c+T*yzg-{Mh7>k@b)f2c3Pe`9#t>bSw&3T%~)(-AY(;T;Ta33(mu{^UypSUp|u^s!w ztDGHIF0Fek{WEj&&=GYX>i%D4wahcjeVo^5olfL-(Qi^W4+h6tdw>Ms!$B99oxH>XBp zD=d!LYllngH>|zQxLF?UJB`R)*UIPol=8x=4x>Xo=S}FM{?fBw2QR> z^PiM3c@~t^@ksP4*7gzijRo|H#4Q4y!l10;A0t!?Hlm0LxJA&i*<60)n>Tlu-xNp7 z(c`#n08`GvRJdTI6mtz_*usD@Js{tWU zlO?oPWu@+7P%+SD5V_}JXDMs&pM#m387c<4ehU_wNfGO=#DN1v*W%}1C&Sl<_pR$3 zQZRLZ(k?P*jpwrP++5EkjT!Q&7yV~s-N*Cj%ig3zq}+e};;XkykB45pweeUen<1lw z^XUF7JYwr4X2{k_uCK*9eTa4HAv{VR86(1dH8j?_-`I?X9u)q~Ltp-M8mfjWQqm2!mqQJb{13y zg&)hSexs_W&5&JglURg1DkF1Htjbvgxyxt^bM>W?v6FLHi0c_}g+;qui?eZH5yUvc z2t{)c zh@Oau7J;Z_bQ{{%4jpfnEP788rFgAw75zWpp}Coho3ng-?_ScQt7lD-qhF5!Hm&Eu&Tk)ev57;Bzo|wpKg~jco9& z@e^KcIFDU76*7hxj$1!8D4DlMy}41v#br=GmCGQwfkIVls}5u5Zk^oEcSOIjDND!B zIWTL?N*7Enlv_i}Z&A2cc;B0DB|$2i;W zN#>p3i1Uu{^YowQGbF^r#oN&?#5KLV_L{2C9bS#t0m@pdyD@7YBSK0Zt+}Bez(#BL zRjpmO1RZ$$$&)G)-=0=Yiyu0xk4ul9M+>Cn^gr5DC0!|;Jhcl7^OBJco0@l<@fd>q z3s$*=R?rm>r4_Ftm(H(Vtt@)Y2v|2U!V|2;&saC)FpTyiPYXD*M3{#j&U3{K4hb}X z8$V&WSLPwGoDdu`vj#5=bq-r?S`b0g#3_@?`#_m^otRd(NoA#2%$+*ZSJu>iTNpZF zPl-fO?!&NSLvn`u-8;J!m zZesE-w9szB@imOa58K&WIu3L(uq590)!N zE~mxO&xiy5qIcqmBmYa)rO}W4x6nR+V%0V33*gWHmz;upz3x<2mUJ@Se79#{cqQMNSvTa+*j{+37XKJiCx#h)uyJ@E2 z4(3!{-n#q7mc3WDY`IZz=JGbCDcH_$`bVz`m^Lu@10sxYa##Ky_OdH91j~>h#)2_o zJqTI_-MAh`&~9i@wUK_t~jPa|KSk8c>`Oin#9bJmF!sV8T}ye+Bg{vbK?($nY7TeV94ApV1#^ec(;KFH4a zAd!uty0~fAuClUSyYRhdGDiAao~f?jR*B8INo*`_j*Tj^@#s6QQ_(8pUUBM*gecmD zY>F7;VN1J8`^F9Ii&gD~U66w+w=twem!28wz!3Q%+Cr&6;N3EkvE6q?`y{>tuYGw3Mw=% zMnN~B56}6kd`y+XYIW4+TGsxKUO@f?tH%<=rO*Y<=72f@HO>N$q1AlgZ<}e~K5&4& zZ=6LRwkLz>LxDzRWJDjR-T=ZD;891u7A6`SC}~qSGqnx+|By+uK^8`~b+d7{#Q&*e zzq;Qh_I9>+upWdu!A9#2cD;u5lO__2e5*dK>ZX0r+R-W>1^E8O#l7N>5}Svl0O8cf z^rzzsdef1_zPOk^V0#7Hns+H1GcM|WX7y=;x&>xq*x}4_Fn9`3^hjeB@Nd;-(9Ed|=g`e%TUe{E^qG{)T7CJSC5i)s z0iQp7Hh1*wI02tFF2bRKrp_b^OSWzZkM!k06pp0Nx^ zA3gEKQ~z#%Yjo~}G1(K64vmhU{k=LRVt4F>%g9$=_cdGHXfOKz;(39osNk zbp>t6?`$W{B5Oy0kNka&3VgKZ9CP8^6;Q@q0c9Nw_`)aF{)|Qi8M9z@su-}+)=k}X zR5KLWw5_&omTmAwpz<7FJ5u+nAu-p2SA{iOWHHe{V46izv+?QqG?duqLk?c0(YX1b zSwS6r+}wOR2F)6T8K1$7S^q8T?O+XDSV-PXA+^|1Q?r{?yi5C&r?;dv$|9gcr?rBG zV-myP?`*-L+*mr_!aCeWvuAR_( zijI*RbnZD?yFX!+-RdsBs~=yMB7xl#RG~i>`_a3BgZ$^7{Ab>sfQ~6+-ks2}ZW?$< zyl31-^q9-hs%y2bY#c`OkHCt4KD-sivG9%vjs+bN_& zza02gdHh0(EAZV=QBkqMw?JK z>pHgiMLBkFCYzzQYX%%h0WA{GV={Ti`Bt`K+Wal=??$H-%l{IywX2ux8f5OfByH@{ z-&A6$^5o55Etxo>SRF;Bt6%PX4~G`8eU1%CUmCa4 z4fvo2R5<3MwPgnQY+?V|St`ErWcQut#47jCa=PM)RQ&j_sq4m%U#~~0y1H3OQBL#+ z&Qv$dM%NeB0(luw83r^k?kZcId30$Q`(>+n>cwT$Q+4}ZU@x}}t#{5mbD`@)Vs^G}sXe<;h9BLmZy?#y5^ ziM`23GiBKx)BuHV(r^^S46L!>tdTA~`#bqg@frH$^&xY*4ESG zq*IDN`$@7_CMzEk#}z5%DcA$Nhl%fc*26@MlCaBX!Txl^X!=?&?5??uK`B~$rtCu2 zsnBr$jiGaorL>l2C|jE)y}cl5^T4UYZk8URf0ylMC(Hc2Dc3-%t zY51Ahab68TPar$ffu~#{p=bs7HAWokygE=mpPp{!JWvW~4I)6vx zu`ll4eHn+pKYbC$#vOrqu$|qScWpDe5i7I$c@MZy!mV{?#^@$}c#-%nSxQ>epSiW8 zyfEh(Q#DdA<(@Rw?Y)&3?&YT!6l8PG&_6k6n6Ip>AsbX8cykhC4-TFD=vEwY{P4K) z1jotKY;`=6N0_QUp+g7wgG;y8yqREEU>mw9f^^rj3;e>J9N1-06-EOw3Xb||`}KK* z!1|U=UEQ2<*o!3+S(X@@ifL;UB?n3N4l1dm@4#{EX3SV@-7Rs}(Bw#WXWx!heY|b^ zk9TzrJ}}-S@tuk5l4eX2lOH`u*^Gq|ax5i9gYQ_MEsC5xJaP zqk~gs*~OgMw2!oYg!A*P60b@GT^8&lMHI%>DkfX>LFn?>#Ki`ki-W2Qrk75vDLHmz z%MWS!e{NIWCEdtZP@s;3Rwr*w&7bmi!PfVtsO(m+X6qCR`Pc{fU?+;1o-${0L3n;m zcThvurrod^>%aW+uxf%!PWbEl~vA6b9=>$$yf3%4$^FfxYs4f~%2%gJk=&L+go#KRHRJIDj{|Esl=;+0a#f6W@uI11QffSsMUh2NcI zW+Pl|=w3oxSl6mK5(_rwqrQ@2Ki<7(;r@jc#F&1NLY&CJM0$!2Q%et}f0UNI^ObeK z=1DP0z#gBZluHpSSF#z{;jbV049uW$p#@VwvW=yUiKW44W`?8L9h7X1m3waYC7;WC z%BEIN+wv3rIR#e}v|d2JpflCd27(!t<|rkk$>6h++2F~_Rw+C!4P)=46I3mci|K&g zf!@5!OfUHugRV)B|?zVEld$ zB$;`=h*O}!AxX}}Oq73BaVA~c+xIo0H_p;Ir^(P->%?h}zFk${88>%vuf-XL+PU)G zg>%eIFcQb4xei}(A~0)=|ESL)zK{b`X(9W2VffIY;SnA_*D(s#FCn3_q+T<}I@0Jld6A z=m#|Ksyx6y+JQ8jQV?gv408o;sGdVF$OkQy zi}})2oEG!xAx?|^{MM({sVkQ32_%7U|5^<@wC?$Hg9Bsg-rruOy~y3{by1UchfN`0 z=)9Q@@ciE6bYoqG|43dN$Ew~-@7$|7Rlgd|3a66Py*{SJI{G7jkC+zgh}{K?+wL!> z@y=l6jeKNCif&{~4mtwjLTptVnTt$^7)D;&p!!;0%Elfo$Xk>D-O?HSlyHo4QEStcg4#B-grZ zE?i!v=Ja8WwCZ~Hmg?Z)!&Ce7!lBJYXS(_ie`9kdSy&F@#DxWgKC)s6yd&d18SDr7R z>t~-nc5KG1ospBvXGNXg9=YkGx34aYp0R7gj_GWUX|y}Py}^v>`WW5=iE^=yo9G_~ zuXRRW>*+MQ(_wYy-kc=g$Zn1uyq(>LL`;qQk2@X)IBt!NUf#`gcB_tFgGOXH|HqvV zpez*fhu9zTr{}&Iq>njuvICDO#VIAhe$~*1b4titv9l!bqnBW>OX6Gz$Hevl*NbRA zHeoy5S$>n&(=qS=)^O4!H9I@D;jjsN-wTuoy{eCI`MXdM?0>42jGDTGuO4*KlJ;?v z<1RAKGS1-?wdA>2jjb&*%6qE$H|x;=R%q3yjS_W~>^O?M2nuWai>#sA zt~QQ^?JRQ<1NvB;&w8pFH0bMc2SRL>2~9HydO}~5M*x2Cllku|c$}TULGaE*ejR!# zbPHAR#u5``BrSq}>&2+b!>om5Excu}j@jtwoenh-t zzc_sI;Vc?8e0I-4b|dU(ug!sdBj~6EeXwtd+`dT>`Z&`d?u5sx+RU?|sKLMrA{&ai zRYJ=;f^#iIWSFG2GH@MiSnr%0)3!}rg39VkB;p;K;6#6x9M;yDJpYn@F`BsoT*YpO z4o7sX%m`JANZ9&<^?GmYSNZNCdUb&105`w! zuE92*gIzj@$o;nD`q>fgo4=Z>tnI~9txT>kD<-v~W2`}^36I9W4mCRQ-bQQC8WBq> z8yPmq2uXW>TCF9s&cZ4QtLP@E?nbQ+9U|XWA1i018X7f`3D)geMjy-cVb{Jk*C+ED z!>bv;HQKVmYqk_B4X7w!{&t{|*6j`3LfXyoSn+2(b_<+GOY1r665=ok&z;}sz$Rq%qeQl*3P z9EX7N9Ea{+BXqN&a`9{j@>o}yR8GOz=UBZHRNHO^;sGTN7T%0 zOfAA?S@vpvtUPADU-+2InRTT3^6$2nf4iL26<4)YVp>&5n@n9hkv88Ccb+q1BHc$T zzo+lil#v1S{l`S2PrhSx@DUlc1R)s9$naiyzF#<0>=%)z;q?&?6~3feVKlErwg7kh zfaY%8<{KDMUMLag3(&*MjudL7K{Gd|xJ@2evS`bW4OvfeV)lPHZRr$Mqs><DS9@>09;|{l2e8z(X-e0joq#bsI4_1iBM_O;6$4Am2W&)(!tRkp0 zg}S<;$lr2Y!*rCx5~e}B6ap8En|Pft25MezqGbrjPDCVj@!YwYS`F#pUA^p^huMJ-vCB8s0n>*352D|V>O ziDp!3dhw6hq|@)8SJQ+azTR?VV#$m?~eC|>hAH>o1->FJ~iFq#0 zV&8C|m>Er$ibQIQnNc&~W?nx2kHc7Y(!p7~rQp3!n)$(oq?G0Bqx}P?Iu7Yyl3Fuw z@us#lLk9Qq@1s`NsEormcA0WKxAe|}oV|zFFPRxNZ^1(O30XrI)wSKePBvD$%$Vg{ zRXTFXup!F>PCZJ%90x)NF|W^38{a!1t+@eTdL zhr5IgRI3lE)KhoW{Z>@EcgK-qCvoY*-TPLSd230$DLoQ1Dd5nS5g0Ue#F<|bq}jR4 z3Nw@QFP*75W20g^h1r=2pn+S6FkEiIim)t~0VN{FwGlo|F_{F+>~@E;kC7q!oD3}8 zTeg#Kkl)XPZ>q+f4!Rp2a+elmCDoo1)gIjCT>m|?rX-u}JS>S~pG z@&;*W7>^*&O2g|OC?M9R z<=%^j4Ouq4@Wv`nSjZHN6bsuXs_TtnD`yRazCr56*)v3lZsM8@DJ}P#+0mm9B#qAv z9iKDir}p1WSwG>;J@d|l%?YRVB|Cpw8M%4F=#0@z@2XQKOqlBxFd%wV$V{ga*W}1m z8-x94M9xk)zbw8qtVOGlOG4-Eox&TstD(SCe$kAuN?kBF)lEkRb+d{eq4DB(C z%Nv}`zok}Sbyq0{+0(D2)mx|)m#Q8@(lAy6?Bo`VWyx;ZgJ;Y0IM#Rk;wIZk}WsG!{p6ErK4$)mCS{)U4c4f?-dh4FTEtM5`g_D5PcDBQ2AWGCS87uDC8=Q<17{!`xgz z-5yZa7QSL1$kYFk8zKgtznq?3Uh`^(sHTFpp`Sv(^gi@oDI$;}vQ^ME2*f3PzeL=C z!RsF}4DgEP@@*h^_{kdKF<{UZpN>#?5RRd&Qj|BcDdIeDw z!PTCyIIQerc=3_sxt*-o-g(0MX_wAc?0Yx&@iyJ%M`uxIm^m*E7a(QrD|&C1_Wq;# zar%3~5PyU<+53ik8p!+>aV6MxsX`YavCF_LItGr;Ua<+6fi;SdjO%}d<+_YjVZK&d zcu3uupbHFihH&&~*F|mWnN9h_B4HkOp+m=i^-qJW(ljqh>s@oge z-%~nEraih_x3(dLNO@Y$Z{NIQ4=3_Q&U&|u;w={|$_A~c4@l)|{AItIhU2f*s|U>6 z`Q$B9_j1Q-RRqnb_@!bo`E;EWq@2K?WTlUkqb!wjKw~VZWmTPKh{n32{sK8lg8ZWC zOG_MU{6cAmmHKSV)vNzrU+)5R5)Ksk6@- zP!_=V-s@syKDvCPn!eQ}MsCGM`nM2Sq>z{f$%8FocVQUwdozg9Cj4xve#q-SXm`<| zoxrle`Z43gO5s9@Hq-@C8By9ksWHBp3AU2sh1{e=GZtRY zOuM$&r>bo9{Hf}P8Ri29Sy_5S?_AdWm$NsA?JGOK)iW=tdPRBCy-oXnS(Zv#eDaVu zU3BT}H~_oqOYEv%{8S4vz}kK^jqv2X%xOW{)hI_?P6DasG{nWx1Klt}dku z!`_Pa7~lV!?Cj8G-n8z;+!ZTT&fZJI$1UpGI&I0kJa1Low&vN!#&tiAj~G3=bEe<4 ziTRe}6+jkUiTMWOh-yxz;cI7`Oooh!byI;?vh zMCvf|{PuZl)wf}laq1tdzKz=r{xdtPM&9J}FuXC~M@02_3bVtV1Mpt32C6(z%lv*O zeXledO05$=uK4?_18*m8OgyvitG^F^6ihhR zI%Yc>gzR;Vhqkzk@@(v~^d)1e14Ba}&RcXQap}~+6~U?Z^2`4h6dH6arMNgZ^NtiZ z*?)X!|9&w;eTSvZ2%q0s<1sgQ{-)qb9`P>2V#6nmXX9Umie=|C+A_W)@#yM?eWR*Xb8?z>8I#}UoC~bmhx5DbXJ7V`Cox{~_l=u@cPAK^G=un^SOUs8 z%AvT;n`!b>Sm|ivX7Cnxe_`YCFrY|z!Jz6=2duwPzPzWEhK5|UaiNrormDi-h@HVqkm@_&Ixs_thk1eKsyXrRS ze}--+W!LH6kAY_*IY8N3{X%)H&EMnleu_)P3$zKa4w|3wWdJLd31c&|(f1(9byak6 zht>{W)BOYNhB(=_!r4=_Y8TU=k9?jx!6Dw#J^tbja)9B0|Du`#9ISSROqIPo>ZSP4 zLYJvhwGH0Y%UCTn`=sipX81&k^^Ty=zxjlrljI4|EE^pqL}-kg+4M*KprS1``T!cY&e&jA>5myo ztu{N(ba`XZfZ?mBIZf@kxo1?rX=&ar%ib6?wahq8)oD(5JwLOvqtYNHl*(7CGa8>}q}T4NOeEyxcL&6kDRBP?fuFHrC^ zJ3f#I?W-oLF?FWfNz1LIrT&d#wlEkg3S)hNH~y`!@e4N26y582d?2}0JFGwgELZ6R zu3;Mb8nr|7zDCkZ5RJ}8^$77Q-l+qv5Krt-=vg0a)B=9#dj@eY<=&6>UI!!kd@Oud{K{Ry_*Z{ABr1KuLf{$>TqA(1jmWa=jkgUB;xSz(d{pxNiVgP` zr+!vIAJ$6F>xx2G1#JMD;{jV&TWk{`tn&!ldS;GL7bQ7@a+VJyg%I5 zgf#2tUwd9S02 zHr$DSb`Wtmiy-i&0-kti)Y^!gi}Y#d>)-u!>D-;x8atmEK3-j19BrCeO0GS6;#N_N za&X`AQ^({@^p`_lu9@Pnpo7P}bLFIh_M?NN@|LjgdKP0A6&S0%u)2EAK#75Lwn`0? zksfx=y6{HaxwMP4uA%~8%d)i_HP2%ShDr7*Oj%a!EtxAg+d`8`f%23lcAPkQ5kHFr zy~59H8uJrM4Yyt~JFl;-vTiD#S`wvI(QzYH&N><#>Yp)c**6NT9zmSm^ zChYifQSuim=fNKFPQ5EDvrg~t>lE+hCGNpu`%J5a_^fpOV0!P~4XF)855mYwj=OKq zoqvC4^!btFeDX(USGA&T$m6!#SC1<62@Slca?bv1-@e)cZ_oMt`|m%Ub#PDLf%As) zled3@ckBiaWA;4?>~;P#KRx#*(^&QfLowUMfq)Np8-C17Ndx@XMj-K&;t2{F#DsL0lg+maL?Y>k67Vb)yf-lZb-v>8rlYh`IXrqB2hMY68{`5k zW!d(N1xw?X5}8)S%#Z)_0!gofhS>K+-Z&{bW=dAa-eqyycfuX`p92kM{B~gXA>f7_ zR0Dj>S#+|6x&5$_DN`)~OrKIhIIknW8y7(QV@v{%Yf6J%SHj0@wv zA{`^V$^$db&563e7KyKw#bEb09C{tzn)Oa)@1C>0yt4kO#HDV~G)NGtVzFY{owlEXjZN z0BZU?l=gnMW&g&C(n@yw@f#S&CWc<48EvHnDrtgpkbFX&_@BSXhg0cba%CzVNDi!8 zg{S}li0U%N(7;=4Z`4hAYD~6Rmm!Xu@-9OSF=z<%-$#7uyW})|oKW|4Hhn_h(ny_~ zD?L9UFRtw<8M$?2DW)=b4Rs}kqgAJ-*3ICwT*Ghh2dljcJ%Fw7p@kkipTc(rYyX23 z>u$spYS~!V45)4Wdowe=>QrJ$Kx8PbB)gO&@&G!lbkF~vxA7;KtcStxS-@re z2d+c(o|Q2sCH$Nn-t?`}FDEeQjOab!*q%z8!@Z zQnylWwP2>1X`;rscmKLMY$T4!I0s%kMuHCeV=Gp>z8?9d(~x~#eu;%<4c&Y!L#*%N zF*bG(S$XbxNmd=^`k_-DmS3g?^K(7D^5@OV_Vmt)AM55eX6#UR8lGxC zV$n2hC*R}jcjl4|achORvLxr)-A}JwyMOx{)0by3*GZ5Hd<%~28i;}jE;}o`->s^W zzA#t5l%{57DG+uRTi&GM^4EBt$xsK@)f=Tv&glXy?g*JUpruA{AVdq5>^?1cdgkEn zE=QM6%o|hpE0AYetmO5p;R8Jas&#Er))?*Dw?gLtXkGB{ZO7Cj1o zi>+HcdixMVV%?6jb;F{wk#A$!mgcCxDoeo4q4kp$|=qZx=HhpVwWCUu?%sD%5VKEoz^>y=DO=CU;dR*4hO=YB#l#LoQ z#y??PWEp}swgyS)^cxNB(3PFp@Y7#suIuOHwLz{8EG$tJfJ)*yL`{R*u#`6y9|`r# zjLh6RGWT4HW?5Olu%W|zd^Ts$2XJ%y z;$yMWa;b=tu>+G}2RyOP&6o$mQWnm{L^7rcM_Kizh9)2Dt}(@bY#0>%Og$rl(AwJAQWb(&|zr zNBy4Z%Rb=U1ofv4$!>dI%&xA& zO|ti^YW7#drkSIk4^$c3ErAvzgXpH6j!m+%WMc8QlQYGeGsfb@Ex!Nw8Y` ztID(T{NRfiyqw9CtBgK$%4_plJQwonJ`}Yg_MCy%P zGh?TCyOC?i-ir>tH$d9~&?fpLMP3wXQGHgFv(-Vq7reWdMx{Ddd0man=+2-o-aSCx z%F6Kzg6iN2(zll?J*E4zuIUq`I^IH}cm;?_khnQrGw3%aXB^6-c{my@nrC;R>ux=V z^sVF4C+Y?)_swH|%^)Z>e)kr>iOFt&(^YGXaSjGfvKt(n_U+AiqQk+ZAqNq-?`Blu z$LntVD#_As$}v)uUQkR_h3m#-`Gy1>MGoRw<-w;}#PqLDea%;^o2l_JpwF!DyxV7R z(vabxmBj;{8Lbk!yBV$ZYzD|QptlrI!gq%8Q%*6jHmHBnd5XqQ|6*UFUJg6a0(|D3 zdyp?(`kieScEv%H&b@xKwx$fSsVB4N;HCg`a?<6g|N2|$kWjjtbkrX<)SE$Dn zzhPTS3zx1AKbo2Ge!T2Mo)%^(r#(O!uMMypQMDBV5UqzYdPT)R(92^TK8tf=ZulEF z17gPFE=19}*O24ku?P{lBw6UEM)x6-9m)@_vX?KXy{=DT)Z^7P+-cQsI2%KTTniKb&U^(&A?!}NSGCabhJx{u0^wVH}MsjfVEuDz4$ z2Rc%o%aO#8a(*w>{q9LgY_+ua*kgZ}fn%&UkM(8!5BtJZdyeJx4S042-mHkbxs%IW z%QljkiKU4=CM0c4v;89m_aE7d_eo9Is8q%l2Ze5$GbOgCsojL(6K2{64)jhK+Sf5^ z*3SK%{mYh050zfC68!dW^iM(al<%3J6I8iRckg;xG-X)!kf}F6T5~)iF?Z^M)q_Y2 z)lU|+!O%SBpm#O+fH)WDb$LD-L4X5q_2GM&wP7&RZQ0PrhmwkV)`7WMm4P$vd=R&M zb;i>dpL~_FX!gJuPq!(qYPIyI7(6rMaQfufnc?ZXx6NB;cQV|=@4zNd1}>FBLi=J= zZ67zjrK9c4!$0_FW^ho&tqb3izHuwk)9GFk`N`K;PEh)A7xD3Da!krHwb+ZxJJLDi zx;gD8gc|y(C0hqRLhmNsH!^EQZ~=##bf_5{j|=G5uY0Ff-J~`LFI%>?cMX-^4$cTY zIK-o0a6dFes@2oVE#`OfO1!X*Y^Tjg9DQ;0n>CaB`V}uAK`rPZzi30wgN7-fVGoxv zrq^ANRMh6sM33BSD3JQl2e<{m{?Ov!tg(lNcsT|;sa5FFn_5otf_d@Ho19nT=~RrV zw4g7V49P9YFY-4$wlc_->)PXRmmd4pCjagjPUkOQvUgOJ=hD!Swc(qxJYol4GbQN( z?=8OfEC-qL5kuph`i?tN_}y7cOVTr&s(X3klYnOXpJZTW8qCZeGvl{@;H=i`_=%1` ze(=b~MA|>2EW9dev`2!kNsSHZ?Ta}fhv>t){g|KGI0kdmd6@>Gn6vED@@8i4y7kE?QQ!Wi zEbs2}2`fFPE}efSdH(02p@G$*De22%rMSHDlfq+%xx^2hJbGh7Xo9=kW!|J|t48<^ zjp^4vbiDs$=B-kwjCKiQj^H+ZL4h%WAsr2|bSeces-+iFN3|=t*rh<=lkr7OYB7>{54KcHn$twjP zeEQHJu8=l-7r!_mKIUj_)EhC!7n6#*njcE3G@R}{r1tC({6aWaB8O^jB3aQ7 z4jv>!4xRj$T#`0wfV!*wmTj8<$|tP>w;ixw+OsH^)hR?VRb1`BO&aq5$gjCqtqfin z^z!Xfw;n9GyO|EJAqOmwLyqk}b>jJqLz@B+Fi-=>Z)`>fh9ebw+&P*CGXf8RStXKWga2c`T#m9kf?G!g3*T>UI z4RPCl^%suTeR33`rj)3Q+t6RA4>0jPYJF}q!JbE{s}mbP6ins*}W7vA1Fuzd5e z2bIVAZ$;zO@gmkzSVTvW;}ZRD{mFTL)kT(GvB%buLhP_d1xWEu#vj%w^9Wtak3iEL zP!|L0nt|uqe!>`-Oi(1uC2uK*Z-#m!qYyi)f$}-z+LLz8?Oc4Ka}I`9Et*easkh`^ zcgt$HN8c9oo1dEnc9FiZ3NZe)K$d@4c`S7tnH;)n+0p8($h8vUy#iCO#JAVfjUq=2 z7}*6h1bcWS=!pY8uZzt^@5I$Ay1heN2TvB84{_?=+D7(ee#z@Y^LXCs0Nv5(#v1(G z3(}jzJCG3t;O7hY8Q1ecm!MlicSj%lncvYT>7Ivd8bdM(im${*x{Q6Yo1BlMhoxPt zg;5=~srC}X27T1%j=UoLY{Rjq^3f{sGfvcDG*|%OP;;n!zRZmg-#zTJc39Q%XM)~PJ((s8CGQa0{bcX-d9J<{A=yQGObb^xoEC%_ue7%M^U3%~yn zSoJruf#UV}*&3suR}AaJ@Dl_THbm}8U8D>6q}yir{eWeSE)g)twY?R6_M+a1{?lyt?q;MVF?vc`wc1X<#>FnBAD(V5cdh%n`I#FV zs)HC+UKka341lT>z9#TX_z4)4XQE7yz=zJoEpPZ6#{<~EB@J#MtGqw^NM23Nfi*{d zeMVNbUVU>FQqQW=ns#zX-LZCuN^$eV%L`O7rz^p;X~4+7bPP-C!_RY=TC#w$;fyeD z64J0wn7f)X7etyIyMAQ$3L5!GT6XGpTgtyp%}@Q4&RCHdv|jZ?;@?+(r%yar7YrwD zKmQta={@xF*PqkBd<#~4k=DOo`8$!#N$k6H?Fmec#)58U9It;5lyp`zIA(`Cb}jH> zAO@cgcykVCJB7h_a`;9rzwCL~Kn}mm;fLYXgz@JgH5`tvT;PG+VMW>VOSEtg4o7!~ zcwQQ(g$v(;?+72$?_L%D>n)DPA6nxBU3 z2V$gH{*;J*nVZh4m?@kJ zCKLR+dM^o<9*ujvW+d*amp%%Zl<2f1ZvDFv{$+J1h(j0p>y8g+`fg26-V{_y$0yrI zhB$h9_VL*BOGWBWC*n#|zbq+yCv{NY@We6kWv~PaX4?;AHD|d3A0*+xFBE;ucnwBg z+v)U8n z_Z;f=4(Yz~rD`zgg`*&Mt!e{R^3a}jkMJh4!5jzEd#(95NZ?xAARILV3Gi*2dTYBL zK2+}F+x6tn4`~~z!)F7;jWq*3@O|@QT<@j(l0Eax^dC2e{EY&wmDt6s15evb04c;6 zW>^=nOtq?&m08arR`jbQbmDmuc-J9#+OY1f9aP`Q>VaNLnf4BeVDeLVv_s35*ezBZ zBX)~~^QqWH4hpKlkU%~XlYb6}{6pklYrQQ0Lk?AK>-Ni&d<`Y>|AX-Y756~hB(4|7 zgE}IV{4=E{ghqReJ~DjsLjw<3H~Bz?hyGQ*YxirVsQC`&zUZlij4m&cJEC zZ@w|KjyHLJgs$06pH!7x8y4ZVF=^4+`7@8L2-zJrF5;p(WjB5QryuEid&4~!_Vu6l z{O0XvaZYXveEcw??uJo&DHgMAYy2I)UzFkV5q_f`8>B_*j4^>EYd|5reba1psGS8eSRX&W?`ca@W*qIM4+RaCSc` zpD*r5G8JaP{yOh2GASeP-iuxcNm}=O$X%> zTjBcZCh$(m6$Yod9L{JK&v#ZvvX!AsJ9g$PFW_CYaAso+;a19A{`^S}XOxTQt(C=m zg^zGJTQOm`?G$c5U$N&7T6+$=346}yXTBk$e*>oz;CY z+?&9=XyIW^;8sd|{`^c1XY>m^)=GB{hn!*Dg?f0`x<8mCQV<7tvL4>8?g^LNsT|Jc zEBp~V1)(eW-_%cWP$ zhOgs(4re<@z&k1LGfhL^<#0xifOl3>Ise~k0`H_)a4TgfhqFY%H)=+|z+9fkjBr~E(6eFt1r$M*luy>}Ol8bw4D zL_wOUh)7wK-bFwVP>OUZQltqeAQnJSYzU~>OEj^?*b<{L<(XnkqUm{0V_r;*(bSh_ zEbLzX-cBN&{vHH6_~qpoIcZR`QJQ)84P|2FV=A{(Qa?}5Lm`gw*w zodZ|MDgHAx@OXwlXbd>*TM0f&^$o38{gAQsi$fF5u=HPhXt)3TWKr{$neQ7jk zAct{VYrSC0MMD(Owr*f;a%TBypGf)5RDUoUyZ3;P(!eoCYx+>i-_<8Q;F>-WAw|38 zAES0){7P*;i5H}DEYwbnHW3UC+Gz06_F+R0xTX(b8#Hz+XBa(mk9X?p^R#yTS9i;IDOqS9QVv(GBj?1xK8S4j<9G3;wze z4y&NN^S0m%AE7DLX`t=FAi&)L_`-6YogF=WoWs^Qy48}cS0Dlw2V98>^$EtxZ8~;~fUCADA?!WY+2! zGLQ^;O0}W!>Xi>)w@i3?<-X&AROfsFJCcLtSJ??$8Xu*>=pNTtQ8kb)%S+q$ff79X zK#mJpaHcSNb#zF};?Ske z2O3OF*i=&gT24rCna@@G;U`V-yNX z5nTSuaa1eCfyw-HN5sep1IIL4j2LQenYysr>qt;t@i@WNR%JBr-Nxa*yAOn~CAQ?r zPp5iCi7N30Fajr|GQt&6pf;M8(o&^$0_jdNN^xl!NV6Jbq&*gbISiKMZ4a6qxF{$t z$8mn#s?+g4mCqGz`nY(`#)N`7^A0<&uiUz7^_FR?eP6&Rp4wJB%*$nMx zs^%mw@tHC;cf55}?DRRb_AkT$*p_dyJq9KUnV#88eeGRl@lcr(^s!V5gGT&Qyx!*9 zRD{!Jx9~_z9M1O3#WnI%+d2!fh>llOs!xhAf_#5pFxl z-rRA)GYxC7m@($)69a`N)ZT*I^X{Ohp)F$sFs5Rif_-!JKsr0+XwC#&_8P7_Hkldi zu>f}+k2Tu)#IPY;;A?{O{+5nnW5K>abDbskM&1eE;X{3cOy?xXG!Yx@eivz9ljf9I zbTT_wnMg;;xgn$sF=dmu?lBt&)c=zEEKW$Q@D~4=Tj?Wk<9Tmv1UxMs`|-B;^eg8` z+>dui%vsgDZ{9C2zt1ly`Q;z~_@x9bssWb`V_si)P?Xy1)=Z=*LGqQjV;H%g5k7wI z1P7}P)7Ky2H>_9Pj_}8Autrw9H-Jl@#rx^F3uqwr=de4Is6d#+*%2PAY7$ZSjq62k zV(XXYHEmjABIh_E^(jjk> zalloN_0ahs7;M?AYHrd#-MD2 z1pGEQ(vyitx+{RYRQP60bkLrN- zKa+smi2NN9`px=_v@7fb1&{cBk(}a+5HMB9N9wh_pVsIww4sjnk zxOtT(lPJ|D7mrDnwq_nFQTz#2B!7aa(m0d4kJ!vFp zI#{yOhtfM)sF4mSJcJ$~Z``%b6#k4`?75;#E9hT*9#x^A^Q8+Jt6C7H$h#Y&9p$ ze#&HP$3-U_5C2p{xrNd(MX+an+bM#Hv5lQAb3nu20pVkZs1Z#}2@A908cPYEA$}E= zyuH+WO~cAn@c}DiD{|j%-uP~A#g_s?^41OGIP*FC>py(w-H#5xIfb*o{Pf`mjjQh+ z*!No_rQ}TP4SaxpdV-y*sp%K&9n%C;Xacic4f(t3#ZKXo?qCdVK+UWE49i8mC*+gQ(Eube0;5 zbMVA{niNBrwv2vie zVmR4kB;I(Dm=!$TDJ!l#nl*?U)bz&u`jqW+#i7IAfBT=WQ49*ixwzuhN%ka@8W6@N zU>uA$I~(=`K{kdy3l?}~k|hVkH?sV)=O!t6!-LquC!Rk*>aztWpB>kBXR8gYxE+g{ z-&#}X?qR0RSgy`B<9>&kNwoWnq`jaLjhrRg(RS(<2Dn3&)e}t3j*Ku%y|ic7_6u_l zF4~Hf*Yqbd4lXJrLt5%Y^^Ue14NrEfPMdO7V$4cEsY6&8ZsWVHJ*Q@{$&!q%t)6z9tgHu&4Dj^y9kF+$ucxQK z>65lLf_bKR%#qH!l^<3_a#k&LXrVaSN zn90<^coPhP_!YS4aTW|VVLp3M^cgeOJ;;?`q^h%Zp2ENR@Sw4LL3rc9f%3H+-yiS4 ziV^9`#yZ9%-9bbn$ej&{oDLvN7__rZUVY|?C&)kES|fUK#pTJ0C!RD|Grt`-l~`yc{&7 zzS0EM=K=HvN=>cchCij0&K8ZIcO!_c||oCwn(F~Lg*$RX-S0(C7+mxp>t;)498N4c{i>>iP07n#3)lx%f)n*Y8IeSCL7_h#5IT zX0FFzlP$q&jSKi;FpEBc{jVRtkF$jo#14x;21aZc@X|1#gAz9w8_?|?cD&)t1vY_J zK9fCykM0o%UTh>M-fB2ho@_7>$Fej`bW+uoCm9UD@5TvJ#DvMC^66%+Ulm_$-bUIz zTKR%$ZK_=swe{9Dt!wj!wy7GjSy7ak58=kA)UENZV^UjVrxqW`f9gV9;+Au9(d`+^ zg$c9Ey{$8nJ@W!Hh3vP^;Yf{{6<%}O3(N+_p5GCFurcxw@%!=};`mNh?OO5b_g{1t z#I~f&+Y)18Ii+nv%*h5HZ}9zA@Q4$zgkMgIRHSRwP*2!8vc_P;^5hLO)6?DCEtpsSFff&llSz;nctd3ZYxI2`p(jlM&hV?>Ceitgrc;j z*IUzeB|j%#ydvh)xJ6!;fN>qicJWB3tV#C)YKEGf9gGU7#nd{WdN0AKH^E1V>&LnE zZSUnSyxbsfUbAlPLSg+X9DUjHPVU0@h@l|t69mD8ulsh})8AE-6$Wp=boxE6e!1|@ zOE2JCsJ*@Y0N}5PBLY|Y9Y{Vye;I-jyO}(NZXVMmi*5dDP6d{_In{CW z*cpp5_)wLfk00Oa9=^FXeaT>x>ZFzp)7=ZljOjnpTdDLMv2TQ@+f;AUL6#PLea*lD z@)caaoDA`|!{2M>S>d-sWMIbp6Hg~f^Xw-kKT6Z=+-FYCr?jgEu5=8@;YF~bBm40j zPj-XJPrlW77);I>8%$nXp4{(=f&Do!`CtuKueE5?adl+CaQ>a%T>X+bi|Oh^sQ=Cn zh8Frq2?{`!H6cny3Ggjt9Q4+Zq0(f*xSc0Y+NUI!w$C`|P*t*S#c=g8x$WxM`ljVe zT1yUIeShQY87{fov(t8nvqo8%3?3T3p-dhfKf!3&Om8l%Ju&mMGtZsB@xEv(=lYZW zWYCf?H)p@vo`8i#-RTsg5VO+Fxj+XSwNWHK9?l(j)NaE^>@LK-)bqRv?F^)Yp|5Qz`R9dIb zLOw%`m%pic$Sbh3W`JvcZLI27zJEYfnTIM(GfEQB(*jDwYJMEXq7@EOevFBfz^xUB z@8iP0rG`@cS{O?2tt+-)KBEqXQeA`G^Dj&#v`Ny6!Y~(0TG5Chw52_vrmJ*N&#t^? zZ}bHnwW}|v`6wOKyQ_rJ|ItBT=z@;<4pa(V3 zLJh|0L5;Ogg<1!t`)V|FkV#N@JmJ~wf)1-@wNWTN$%^H*HL(7Wtq}H^X4@-GOKV#L z(3-9+>b<8+1I2r!Y3Xij0J=Xi4b*>R8v39|nzkow4bT%k(zN|yYk>afk*4hxTLbh; zk2Ed4Z4Hd{+AitYw0)AEJtB=#vM1E^pE@XQuawtpSYOalY_FMAf-bLlfi5p?om9eT zZyl8K4udN0Tj-#)Hznu;29+!Timzk=j9};1^n{w8rX@&Fii4Eb?AN}aqu%KYY96YC zQhcQnMw{uNv>zns7(FQM0SRiM(B-9VV^GC?wGK+#CP5$QL1{lpC5+QS1y>Ces}P-D zOzKIk)0P2lSF<&NN2J>Jk*cL4I37jzELoQdYW7OiQWaeP>*G>E-N(EOD)&m&QX9Mv zg}EnITB?Kl`$*MNAN-GC%%1ORDT@)%jT(~0Oxr72%p)vmAN7Qqw(Fp@^-^B5Py2$7 zVlntq3A()I4!XRwl~M_#+0I5OFKwL!9mAqCBq(i_1hx2HR|4fJ236euN(ZIgAE< z<&%AUCQtJA7B@Ng_&7NF`X+oAEZ#lU(@!mb)n}4}udl--AMH1pB!1(6U)`^p|N6hd z2lf@;3m;OTL4&*vTpaPxFIT)9GW_r0lYQS`{Yp1exx5hQX-)8LO5qV?tLfylBZALqp z<=GX8Kla2~_@|eHqnDSXgO~Q3Or7lHILR#}W3tl(2iMqH>Sg-qgUgwhSwVUK3+7Q7 z;X`?;C)D(e4odl1%4^1M(~$D&prbDLmDfB>2c^6(l`wj=4odl%LFu`gT{uvFmY@$9 zl=-O{zF$iChSR(~p{7g&lKfb-ZIW+FYFkgJ)HVr9TOs9@+SU^)wXG*qYMTV5ZIeon z+9pBixR#(}%qhMSl#Xi&YC+fCHBd?i2G!6(%1h}WK_xm!P&%%q5@0)al|aX}lvk~T zvT-ft1>wNAQVH5|?eh3>O(dTw+?v{>9X0-DYc{%le8e_7aKX5V--U>Oa@%^kp&vQC zH$Tcf{oi1Sk^U$QNs|UKa*2+2JoKM0{ux3({5u$8z>DFJLa>X5+OZ$}-;RBwM^Kft zPzeChM2e`en(XbZl>qrx`V!#do^AMR0U!=~M03DBl7E(t7s)>>jhCKKX}m~KI$or_ z(s=0!mBvd?s5D+AC><|S3DS6xpme-QP-(nKP&!^Ds5D+AC><{hsu?d5l#Uk(DvcKj zO2>;-f;3)eq!>MMPl7^UkS%8;hQXO7L32a5!rw=y+V+vEr6P1IObI>T)un=(y;8MQ zg>Lox<5EH0$Gi(F_e#}L8@ko#-l7Q?->Dr0GwsBM`f3d=ab+_O)MvlkjOaa#6sGZSjppc1GXBb}hDdQC zSve(duF|cgMr6m}-23+oA3H0${?W63 z=tc|f8?qIv_jj-jeJdFu&MD_@%h^p}n!7pGCBpQM7wHErcn0OsTg;^07w8m}L3pfh z*b!`QS|Xkvv6obm4AZ?WqW5xg4reG^ihJbgs*|`8Fz?~+)k0*)3EDfA_%jdX(6h|U z*lsPlXlaG>_n|lrr&~D)?Jk7*<8WCXloIBx{;tIrK}h7Yr+%(eJzL57N4KOdn3uUJ zR%~wOU)+5mp5AkidVWL486i~sYW`9W^=bE7@`*Zx);CwWI|CFkkXgtkf)bSa^g}&A zSY3oG6LT1I`a%aAs=rZ;q%2=f7UNUnR+E>$I(6(B``n$2c70yF@aty|eqDNc>vPAp z?LKsDn;>>%3OhP7xrmlO&P_84ugjXA*An&|@%;2d;(vziAR9)k#LuCgNn1g{*_00Z zK?l0qb{Obj15 z(h@5K|Kw+gW65=6)k^ZEn9Dhc)^+3y+)3H-`sQ_lZ^tFU4OnjiN1K78=|0*qz+LYi zWD^9D4I7QU6Vlo})^F{&_%FZt=F5NIy7lj6EfxVeA#}FBin!3JRkgaDjv++Q2?KyJJs}h;bBJ}Yvmw}A#r<$l zd?OSa`cA2CfqgFub+0WJJI1YE4ZmLnhQc*q33m!?6uR2L8PJA$3z9pOYTle#?b%HK zjXxaWRvW7>@A!PfEQ`8@*|mOU(QnHaWgaU`eg5Ka+c&Jk}9MbHl=0ktH5a#WwE?TOM6z zJS$*PczZ!&Ltt|JTk=K8J5yp-#XqTt+?c=U)x!9+q@chpwHc*OE1e5wl`i)2&540T z=jbUt=*vZ*3}QVIy#{Y2yJXaevtBEEk?I>hCEmq{Qx<-(Vae-J^L;iZtZMf!3Gzzu#NL1g zapu^OSr=BX{-88|W~Q&tfjvdbl_n+}L^F}?2EU91j*_*gasOg%pDk-JGU@CfiH3BE zVW=CoJE~!tzhmyy!fi7N*U(;9=T#V*zu#F1JXV;0JiqL%MN5wrI91+~FS55QH8*b+ z@1FJ(e>%6Pq|SYLW?NZy%0F7$ua>8tc(C;w67?d*^G!9!2zHZpQ~CpS`E z#XA~J7G7Mt0^D5(Y#o5DIpUk$K^rXMb_)toN~^ifm_FzoEr^_C@se(Y`rH}Y!>r@) zE?L;Pr|jdF)(;nKsaa4IQN1xRtaWinWy;eFre=6o7cP5ls!Q9#)W&#w``PuXhsg!gZA_yU#g#X1 z{0!&hmrKza6h}^hdzIX*-LO{0j7teIr2&mSkk)0nfX#2un|)IJ{vUR45TQZN6OYQ& zhNhJjIhzBB*U|EYC$kp6BQI}KJ^O+9<%N3J<;pF$kER`cfA0QWJ2#YNw8WR@z0uVA zPEI!|V9KKTdP)J^8Vt6gqg$!9;Nqqy4ch#d%#N$}^Q(@V8WuKH85Z^kdGM~d2;$&9 zb%huh?xu{0P`ZWFSq@`R2oh;9n`SV0*Ts`NF{m;G;75~;#$1cnq@2hH$ z=vFT~MF6se?qQ2{#wT1@+^Mo+QgJItcNbKHN~e*ExP7FjRP?NUIcJ#fimL~>>|v^pj^17yY|^+O zzBRNk=8{mAv^&c!d%?1uSc1Y%j4W zMfU1RVf(rhiEV`m4G|?DY^-`WBG+eq{QCAStMi7LUMz^4n;zo3d1-xB!{UX>3#R(cpBVv))O1b|f>3{NX=u1kY~hVn?!0U#F%haf zR9osQ$WqleWDVI!F+bdCA`Ad6|DH7bVubqNZux%Y$J5I{TwC|b%pC8vsVjE`SIqF4 zJEc*`ZV+?LM`XUda^*XahS`2T``YtrTt^J&w*UVn4bOBM^WQQ4!I|cW$h36jzY_;; zB{$WJh3pj_lU;4mAC5<_Bt5fg-KMmH&2!TWFD$LUkpKUWRDexoC6@AQ$UrP@Lg^Nl0*=tOjB$F61{b$T zQ8y{~NA!#tvC-i(qPGOC&dOdL9K1R^YjqIuFH6fV%q`9-O>9p}YEMksoS3i$w>v@8 zM*?3LUxm6&P&2g)m^6eax0SrJsFlz0 zYh6mR4Ar0Qe%9Y>>g05Xtg2%xn#ft7j5MFh-1Op^6CGS8xJ9gk%88xQXv->;XNU6G zTp+0rXoXIz(n>&$1DMOLYVwVo6T7!1YOhz)q~fU&GeSa=2M2luR4L~>&kWkktxt<~ z4Hz^iV0vPSn@_mCoy+(s6Ju>0;;qNUOm(ESB8rw@&22{HBuu8~?*lQ6nP$jW9;k_G z^GqB!PdRa3fbRU@u`?zmB?}XCXZS1#!sd>=b<;!JirveducfC9 zwDng8h5D0whC|Y_>>S1?goNZyP1u^6usP9ewD@cESRZ@e$?h&_n@{Jje2LWe8eNaG zUx%9)3%DtRr;!_rGGsh41Ad!W-;ZUwyjItfbQPxQQSUtTJUcp(13zeaIwfymwCC)( zM_V>OjoU$ecU9GIDXU0Z932ytAbt=wSE=+54e=*;0(=yvVLpk43*x3m7#aq9&q&J< zTPBPjV(o7?aS92sur)Nawis!L4&;b!=UsjS@L{(BWVyL1yKz4zQn?YrDYUvBDSGy- zt#d|@|H9zdrdgW~bcmg&osw+H?5N5)5L;eZsF|5J(9Iu|b~I z@(SdElwc4g@>H^NASD=NT-RHW5)9(Qz0a3mZ>IqdDZzb-y3CMg6Dt`~g5|-wC%=I~ zASD>YipvAea2`>~##Jz!D|k!cJ|Gll3UT2ofHTcQai$PEytRr!D9#jOgFLI{R62gU*W%>w{yj1OysA8F$yCfFh zc^`V;SglsEHjlZ4rxqXFLTPU#b~tDallB%!3OMZDTu zwDFzacm9F<9wlt2bgNhXHwB$PL!_3qiq_O(GPi@K9e-K;P5`OXfM|2(7A1bXHt<)6Pxk{$>wV0`*i zRg+KDoY{L@qxN9-Dw;ZThOQ%BB7!#Y2@-0zUK^-IjfiQ{ZvL3iLK8F-n!WRc+1d%M zgVRSC_j6na=Y6K32zD=a=lJe3YxikuG^3C-koftJnZkNdtfTK4jqltCE*qrbGA-@; z)*8TkkHaj9l1?4r+g3v|hp0d88jRJ)mN)V42bN&6O|Z{^jfly1#+X9#t!A>VeI#Rb z-0Tx+zVi~OcT3aXGyco|etaXG8F`QX#ZVCJ|B~>3!4C@_(Xz8>**$p$#{5uv?iS;V z?nC4+dLfGSg0qG{U&YYjt{zx2tCi6{WV)Z1R?#_Q9&VLgC(+(Qk2}?C`a})h=V8EY zyM|}&s83#xYq2AMs(yc|3Q2-{mn1K%y3``?!bhn^-R6q#{z6B>oe9A4DTd=%#43bI zINChE&uR4g-@!eOk@nrkQS!NbkhfLp8QDcoeR4KqUDEWySoj~OcJGD%PTiZvgk2Ns41PkiM=VwS z4$Kbs^xIWkzqzbDU90*fxw!{m+;$f!_y4{gDDV6R{c=S!VgqC|Wr-5re_KlbcMS_- z4SSxAVkX7ClN=$%Lt%pq3G{>wlEb9z9`17nqvL8&8@(Atk^+JsqWO5!+d5gV4G4pRVDpIIz7bPBA|gDd zMv&&nsZ%2&rcR9{Em~Nq`^=f{QzIj%_V}hW`4BY0k{xPAKlmZcT_1PugyEK9>C+-2 zrcDhG#}aK8zrCYvrqVq!(p@=|y)Bk=U+}jyZyQ+|b$ff4>FXmxX=c35^;Z?}ZRGk) zcV%Rx(w)97I|UB-3Tr2ly)Ui0@y3{uUA(bROXE@LMoccQ`b5g~{DRO!A$fVzS7n84 z_Ff$SaoDt(GpD%&!$tAyBGW2kBJ*N`BGZ>AMkM;rP7aEQ&q?iAs)x1gBb=@$1J(nW zpFyv$jOZpK%`yn~uYlg@P2l3nH8S#rhqs~LkVaN-+$WV)CsIT63#Rk8w5<}YW73z+ z4Nvr+lN1ylpPiNfd=|$><;4b5EBYDokT>8HVej2Q^M`_$v&dOKjNi#M!>wBl_edSwH-m(gVt(VUQt`D6GE+R6L3~ShHIhvfr!@6JKFXk8LTbj_+Qk0bTK-In;^^nCVl<}Gn12<{!U1bCCjzURj`JBVLQYZUc>90A zGh4hD>3BxINL#vS70r0nZ;r&Pl!tXZ^SmsXdmxl56#Un+GDNbZ%gWL3u6X_d_pIWK zicTM4v?7>NjZ&t?pPvz^u(5nF97{IcXxfWzkcYC>D0`PA5B>Bc%U{VuGO@Qn1TURc zALee6j}!)ihsJk%36Q%Cf{udkmdGB6clg+!WH^~~^BXMs53f&3JNxcEjGehC>5Qf%7kXj@j*EZ` zpTj{0JdSzJ+glL-)VI~u-#!(ezcc#KH!{6LQAi?)5lTy!KMoF?C z#9#SFMI)02##n?iF&fTR=nZ%UmL-kHPQtcJx+LI=I0ZZ27QsP{p^Nw901BW*?IAE<ToL5y>t#+1b zj167nuK-^2X3d;8uHSftf5i+%Bdt)Z4NRHb;FJ<1*3$~>M+JM6Z3zpe4H)EG7)!Q! zF&v6JNAg*URC>N@kRd_?@FB(Iu6UTtxor@<@xe7X$O#EUE?+5^A3a+YAKq6SK<0>t z6{+{ntykD>lo8Gy(!&9{5Sf+E%HrHKsDtqiw>7+>Vaa`r7P zl*$%JX_iv_XyAbbSIm-dA|_`q6zSga6DDciL7VJ_<5J2jyo28;46X3vDup6`0BRkD z6PSrCgc~R1a%Z)*h6rQ1aT_;MnrlixPKb}5&v-La+$4l|j?=!G$=?w-wYK6lq(lo? zXh#aTC!L0s;3I^qM(}r3BX;c)f7!JQEhO<(C0d2g&8RUfzjMnjEN|HNw2aJ2uvPl>1~{ zLR&O+8nFFbY~w#>@1dPt`jzx%mx?7l-qS0G9GmOq6ZfR?{<>a;j%8JNIB2S%b?`6o zpDM-!H`L+BtYoNzN=%usuWNrJf1 z(1X>|^+f4@l|PGG#!0o{raDQD?Xx9!X-kHT*jF2AGKyB>lklVoYl(c5_w3o;W=bas zdCP83pzj%jnkD|m9m^7TlXU!g&X4S_BK!Qr zd17YQ&tB#D;YbiHUGti+S>kV5BwgH{)l7e+ihHxTFtXE6OsNvn{SXkL{YhI=DJ$fa z3?D5vyfRaKnj~h5cc1lPmHUV^+DkvDrarD-yqif9#iuh-{%#*uz7I5#5dLL87pGgX zG2_QWm%=}iWAX8rbE7}9;9utYsqfPdE%iTm{0GYmE!~;to*eVh7%2xGrw3$jgIaYM z7f!OoZqHNbGjMtv*wb|99?vfD77%i_b0T+(kHu{O=wazhCu+LT;{~`-iy&o^SBk4^ zidT{{$b$IfZdo1c7P;kARrTpDk#4c8w@~~pp@h4d5@?(g&c>ozEIn0-%c3QCC%d{P zdrKwcOC_AHt~#YHfm1%qvIqw%!jUCv(p&jne8%+3jpw#r;UAB*?L z5A&+Z%Bu7p#*w&v{2N;oYifOy#H5-UBc?s1CHvR8uBs->og>{wHH>nJ#BohaY8~%q z80-Qr>Q$Igr?Yt(bm^MEQJZ=d->M$S{XrZyYo>97;QQwcpfjqrV=ljfcW7iLU4hoq z@*VFdZ&v1EO>ICk^o*KW}M$!r%ulaNDYjg%qb(YlgXZZOT4@S7V z1HH=bveNSngbK0;cY_!B`Ys4&W)bb@1KlhmoQ8QD7Oe>h73}yMDqqYtCTU(74GCp%W&AI-q_~PyHNxRuWxr zQhI`}Hz|E_{wPk*AU{Fdw&QPUM$IioPx<{%LGfz%0cbowl@oALb>qDrJ|kQ~+RcYV z{?M@9y$5>EB;khMgO242y1ST!9?y_iR-F<27xI0KUR2J})kqD+#PSAyPc3=xez3v0 z`@yFI6hr+)BWcKCY~Neh?M-;Q^xvgrsLbj6g7xp42j)p1sf>>|ZdCVgX(83nkueU_ zL64gM!8jy;Y6zkZ`ClA|g6dt!E*dvYduX~W7CbLW1wmgbAgUcF)98EY{+8?@8-S`y zbkZzWjpJ=(Ou@3?Cv>hib@1cb!W?r^`Qbhx8KLmZEsc*z3Y?uhcxq+dull~ZzbA17 z6^*B_L`&(IvBsThbaX?pgB|*J$QEk_*g+z#pf^aNjkIm%>FNJzf{Nl6)xD{)bwyS zA>4+?A|n&fQ_@NX?I}N51m(&{`pZq|DAGvXp0XLPOMTh=)T1!$$W!fPJSiOQA(*Xl zi&IACSu9+?@k!09$m6@1+=hJXC7R8qHx<^+Umb0!w{RkKybK<=q*)P=X#VI{GFgF> zWtksH{LpIO^OKq&SJ{nttlUd!&CMZpz)cVgBvW74^OARV zsuCdguQIv+bH^{zywo%q^jm?|77nW|Y>!+3^@{YzIm;#!1P68hx!eWSQ1wc>03%OP z=N}bqmXOojf`>75H3nsxqs*I{G7%+-x$fs3bgugl@MRL5&24u4&ziaJXQrbQ)m?Cq zv@;Jg9lPzWh}-dk`iT1Q^V|-0+1=Y6?(%fhp~(sFZ;nhRPxr;1UFy^2hH$qO?i!yi zjYGY}4d(7L2=(dSl#$LK;oW=#r|!e2N^Qtt!oRq2ZEf&T$R6lYsDI%B|1L}E?4{GZ*mZ5f9aKVr?VFK#!-DQKr#mRL zxM;sorhd8nIqnD5B>toOA-&4ijuDAM+Ij@l${zLT>Ok3)&g808W``*)^TEbPA`MBR zTkVh}Nt(3UA*H+_t%GP}j3$MxkZ4k9M2SBHlMFk`TxW`XcdaOv4$$MDa()j?At);|9 zKz6ezr78b~sx*zCgg;`M>LY$V{&3NhuzY2Ak)w{1_`#r;HBR}#thY^0G#Ui`mhAJ6 zg{lz#tSY3Rp=vt+qG~$6*|TJ;kLX^XmP@FIx@gg#fh-0Fth_r8@=WBm)J*0pV3;jzGfmV1@&=2tGvd3Kq6 zj`)dz)1+djvG0BO@ym8o7EPYqAGh|78$ryzZobntluW`jhsd^8+}`^-G;v4RjM!oV zr@?Nk*U zQsaEG;H0IUt;KQ9cxheT(xod_2(O>Eu(q^1S#aEGS!mcY=VJ>_SmHnAb6z?lw8rW5 z+N}+Z?d^>XTOpxjP2v@ts<;;x`FI*#tEGXRp=Kq3HlJ;3GGRx=Q!?NhSGt2oIw_Vr zwfLNO&b0cltmg{m99h=5{=XK{9z^Fx6e{+L9}h~LmgnZzUv#&e zzppy=nT3Yp7sR}Osb7)r?0($%X=m2VYRw)%96CN0pR~UcyO`VaWO{6Hh66BEi6#6A zHkVp}a?n6KlRF=ehWLWUS=eW)CneHFu zsw4%^b8-9=sy|hxTv@Mm6)#joRlx2Fn*YI8<3%?0vcHT*b@J`PdyBJ)S83tTS$Fb>kX8+#+T>a+{~93tYJNDf09V<>Zoit|fbCll(m5R$x{{oC^>aO-s!} zsgmw9nne>#5m=z0m7$Gh-mt?W4%@bEWraWyk9)*?^)K7ki|4uh>LfB}=&rO)vtwJ6 zafrtISNFXUFUo%|FDHZQ>+9VbtMivCQOh%^#U8Z`LuBA+dQNMMD~bef+S0vunnT2S zO>LG|JapHWziitT&{A=I_&X2d%RPVn@fW^8)y5ZyPD2Khtsjc3ILCEMwxlecRvSMc zx_0)Z*G)+?YMoqKre3Jt!-dhF*@Rl@$rz|l#~0`s{6o~HW@8TR8|ta%o-a5PP&#E{ zXnqmdC1yCxDzaPDB;)YeG5!qfuR!(GjPp6@# zNYs>$_R%?);GSXn5986&mHuE~)_Xs|oXMuggDEEUw+YeLEpF z6=!miV#@*|l_dz947D1U)wUpK&)iwzCH@``2|*rnLhQyQ?-urm+er3N{A|iSqeYe>%*&3T6u+)g z=!qU(W$;Gy{c3)O>S3?9QNM>QRXCubiB!LaF0^h!f4|FJQ|F>;(#&1sZf@L2w$e)J zNA&|;i{;SkCj>vNIPE$lW37yI}_`cCnPMdOGL~GS1t40XMiUTaVR44g?hl?9OCal26%{hKTtjE6HiUTI* zHN%I_n(^nB{&{U15WO`3(P(@7-GS7l^-3{tsPVx1!r0bgpMH1lIV12SxG3vMh@R^Fh9Pwd6I3mi@ zm>aN-B;4-*{-3XH(3UPracPJW*?8|79ox#ZxnOjOe!{SHj6T-JoFuMlSQfXg$z1S|x2-Z^UXx9{)*>n3^+R zZ}>^0pU>_!2zi-P=Rin+``|n3qmb6L`W%HuXe>ET4G7hmzQ&?A|Dnq9k1>kNqg7Yv zm`rGno!v~wq&Q~?JMCt5?}fN6OMmr_{us_8PdFdS8`!jQfyV)lS~R$ZMR zt4JeZ-lg-Flb#i>sfBctGtx0ElB8j^s0KY!hH2~RA;<*T$DQ-AQrSbo6G|P;hr3Jr znOm)sFH%1XXLM4AO4%-KA!R8=SS$iXPIFw09-bX<_tmu$ibHxyTIv~)sI4iv?;d3o z82)G)59v-|p~tL5{RVnmPR9s8khZ*x%}wF_jGpW*%`b=%m2DRsgaAnjp_LFSU;;yK zKUpm<+9@s}^+JGHvQ8``YuC}k8;I;SXTx8@&6@E2`GLy(CG}|T<@R=@JS6@27x;^; zEE8%W!8Wo}n(z_1ckgQd=Pwp$9}4J*x-CoRF9|jHMOVJ1SwS!ALf=zQYa%5qew@aT zOCRpch7IBi5lXsuKpDXg!LRUe{Gzkm$9ho{UGq)XT%!q#K+PY^rebE=j~TlkPQqi9 zq`b5y%kL=hOqs&LHBicD-pr}ZmUPA1eq^U5uE%5?8^nTKz}wE^XY0gEM7fTPSEWjt z$}7Z+|BZhZG7>ACep1vIGfX503^js``h=3#J>!GD#!U7evCt?md%8!0=3!W1PVggB zIOnkrV?FIXZD%RRP8{nw-qS8xNvg&=Sb2{3VlYdO@m_Yb5O_gkapY|w0r6=Vfqmme zwrhgWY;{3uekpc~M@LulmNX7+x+XR)eY%H71@m(l+&r+!=8W zF~jT*-@#~{Te?Bw3g(69o+4Fe#9zc;Pm?Oe2K5GVO=Op^^PRuTeiB|12<8^)d^5Jf zF6sHO>vVfoOuV@+9|H|i#{*RaoTuQ%9)5LkgQrJ*{(@F_%h-~c#f=`G^?3`LJ*;Aj z)jtJ?hD@I}%hPQ5v>48u{xETm_1O?2ki3&cMJMOi)rBq!&O23zpYeIx0U97!$|B0lviDStVhQnjq zFP4^G+!7nRg?_ikHWj^8Qu0!f^jA1&FN%q(fB1?w$CHu%d_WxNT`!w0OoV~KMxjLS zS4iP*@m=wqU8Df|v^yWHI>*0FEf7s!=z&+D5tjO5-GlZRN-&2cq8c%64^^+&##*g< z#KouVUlP&+)f%&HOURP_LQQbZQ>p5m+`QRqVq(_JroU33s-gRkP?|ML3qu_rppLzo zI-qMZZE+N>qsx8OQ|s)eI_fK+IxX_Sk2*zEF|2KaPP@gfCU0gNxuLEqX4OOXS>dJ` zOMI+cg{osui}Rm>k7oUYZN`df_GdlXe+eCY6ZxqGgc^gzMJjKID}Pgcl&lrYxLDP< zxW*_&1f{U!1RVv893ig>C8B^^|}+5F&L ze&ZC?FN&d*)|wkbS;Q#4g3SP4D~aI|WCt|q1xv%>9Z(wb7p;fw9%3eU+z}a-U~4eo z;KAYHk*TX41atM2oFiT)rn$BeNe)Wa1Pk#BE}m7N%x#~Q?t{4rlJF!}j63Be=usPB zHeBdB&AIE08(Wzj(R%INl&-e6B=iMha40J0)%ucG%CeuGpWZrYpm<$PEYj;63Zu)s ziEpjEWXihB;?380{INFoVpIK_g^2+llhJ|do9)dlhvqz2@0buRY1q_K#h8J153A(B zwtjd1cx`|$S`W?tj*z6${D%#tt;hZxLuc+l*6SPM_kCTyjXVE=_`$=ank_ksiBfq& z5>`fO?@-Q^7CTXF`PW#x++XC*oqzbFe3;(CB)Cwkxq}O@YON=5O00N?;s)q7eJHgs z6wQEsu7yIn*>wI(SSN4L%+C|3SDk7aT~verM*p{+PIfUOlOE6fuLY`zT;9$jI?Bs4 zGE#j|^TRWxHYlhzCAmI0xSp%jdyqE-KWq;sU!~@z7i8oYB=NG0?2LT+YjJ$b92^)p zw=FhqW4xLqw9LW5fpc4D$F;=62VsM|Zkt&Ak`dMd9D#S342}wlI~AL-aw&gF4ir6o z<8f(d=Of<}A}4qJYYLg>qBI(+baizzgx9sGt*xkJ(#s*`iT!i7z_i5!6Q7gu~FC}=z3htmr1D5O>DhZ2F>M~(I`0AT3zUn@IGOZKZ z-HY3x&55_jVc62nkeG!W*>254gn<)|We-HFG zpmrwh0o*|N2wQ~p0y)$8ORd_Xui{s%csh`*_T_B4bqMQ^6X*{ov~{nxt=*tMYoWlS z2pBEv1EW4|MIA<@urEud3!`pUDd;>ywo1qr#;|rXI@^HGGlWs%v}S%?OUp3TZGNQ0 zNvXIJYzZ*`sS8IAXCLF#D8)9s4J(MooAQ=+mYN`XOR}b!yxi=kK0Slsl>A zCvhljz8=mI^m3O63|!k4@d5hhg8nkl^>?7Ris~we*Z7@yK`WgF>F^%g(N-r@3e$vV zsfMMApseH1s6zP>syo87qUmAL^eNI#wxE^@k7A83GzoWdD>Atc~ z*c-wnxsvWH^FtISGyvcag_fRA&6Q+{uZ;B^`SeInEAiDVxl;X639%dPClsMMSTBR|i+!$yo5xwGZ!96^<~}y6gM8d58>>;` zP2qR-ZuRawGR?wcM4OSh&1eGEhvG3Cc;rz$V$cqHe<)7FcEe?VuW}CtDfp3lC#v4> zN2E! zIhOcmsbMo@5kD)>k-~pEPCNRU6T1@iN8F?m@!DwL$#i32H%u_oxw)Ch4QzNN-7Ula zTB4SNB&4dJ>V1hMLSBgq9w$l@KA^vtGpQF%PzF7s+ZYRICg>tAVu^Uu%-Y%D_xK3yq*A0Ag(wwz$OpSG9pe65gqw*Z`7n z9Xoi=Gs8j5?#~BE6j618BKfi$d64iD^9m3E5{f6Q#G%=zo1tgT0VU&FPiKg}ZodW_x4^+*O`T=;l*x!(1R^|c8J8Kir3X2m4Zus9Uts-^czLSmD27h6|b86IVw^n`+{pr zF%BkT*WD7KLI{x?YDWiTpbMb&0`-$)*D5^~zduK17=L@`PW3g8S9gfzWQ|bKai2dW z&Jt&lEN1IZ?R*{bc?Q-3vC|+%t~I}~oTb&fEQulcnREn|1>yhAn@V0REPSyVjywen!PG*id>b&tjHX?ok>vnd0q9^kcD>3|UZWbr zw9Yq>GX;7g)&1qv8I1bKG%n*=)vpBG>d141Ki+YHd{2v}GCT)wRLE0k+1l0vy0-IY zgHm}ZpdtvmGgyV|k(7BCJKe2?JW`)HTS2PlL7Fa@KkLTjWV@e0{yn|9ahTpZH zk*LoU%hg9!77j|K1Al{jA~tlK6M_+gbzEjDmkIAkrG=t*X-QZaw^Ty^f%N8%aiP6Vu02uBaU!V_-ccV^A0%l?2Qtn<+3;`iwSN;>;uN<)^ul!wZkVMgQkJwlIc5=p z(gsv!A3}$G3OL_@O1}Vz8ykG+O&0h+jO-Va_ zh(3|JlLiB+^EyV*N0{;C?4AdvR#!fRCYAd55HTLPG{@uolglL!JZ3|k3}uln7;v1Yw!d(Wki1RgR&VEi%KVcR7Mh!)y= zo;Hy8RlD$U@3O%onzHGPqMhxfi4BvjW=0|U1wI&tIfaa_QQzP!YQ(SU%%}KKYM*`$ z+If#l*UW?(&7fOr?7LdSci}-f9^R%Ha6A16x?|sv4`*iwUC7SE;QD=Q`cb^Ynz+5!A3pW~o3S&ERa?_2o!tdXnCTt>E(m$!^`HC+YWa-+0Y{x z39cX*j2j<702BD=EEP zC5Jn&Ua=oPF7FpNDgH$%4~5fyijB<_d+{cBp5$D{e>t1>)35#95ly2fPBv*XnLH7y zXE!;dKcjS?O1jS>R931F3dhAyKocsxpoMfqiJ#zr5BQm+G#Rxp5M3mt!8VT9rXY{r zTV$eY316>GLoU5E1bjqchS!vcTzYAI{X=WaU79rH(n}ML-@k9rPn(8ZdTH|O_ulJ= zlcXgqkxMVlpx>W+(Cu57b4Yop#)4eY9W$9PM%UL}B~ct$o}MN3%JJtOsSH|oZ^|%Cp-FX7MuQ1q*ixvr ztr#KE!ZAI*)2pc?iqb$+(_~pDeNRyeS{ksGG%4nm-iKm`)g4EyjVU3Md}IN#5O^db zWijwd&XuLg=0U&Chp%j*Y>})Q5qWj8M%fzN3)L#yBHNC5m!}XvcSQD_?3C<`>?PT& zRIXb=u3NcU;=^lxYriR+ezecpZ!KK={r>{4t%H8+{}zsCs+MGuiJ6(1BX%>Ok&rc{)sN=51B&G+8hjQ_~Q&6~wfbl+UO?pb|Mf@@*)nXlix`TrH1 z;-;-jA5WPKmXaRtO3|A%!ux-p+g_Jll>MLfz5_a{BWZW~rWpw#A&s&?SsEdsgu;Mw z0!bi1LP7|U1Qto;oHNEO$s}WJ9OR6>!U@~3{_S;G?8OOZ?DcxRUg!1NUayTYpqZ=p zRo{DOMnZV~-oNL(_s;o2lkV+XT~%FORbAa({fg;z%#^=p`m^b;rcW_%{}0nYO+T7` zHg%f1FyC!veV8A!!jp<%QSjSsEQO_G$)g?Su9%gxN_g^PSUnCEo5-fJYuGF{mn~#V z*-EySVf|^TF0nB^q{NU^`t+0@&+Eo_PSEk3RTS zdgW^R0BY?2V`YXDTyp zHeGA_jcE_YJ2#kaGTmyr1NoWmM^?>8Oplv>XL{Q79M>s9*qVCPS6ogUdTo!FzZDPI z@e=WpJwBPoZ~9L6|I^nz>m(e|E3f+ROlzz5$M*4W^x-@P%clJln)ucK)D={v1I9PA zg=}W;|GZi*PRAYgyzwS{r+rh4=;HtBFE>1RVF=wz%cLPZDyOeJp`25+5=CfQ^oJW7 z8gBT*qD7}~sIR}_v^2!y$0E8((K9!MILJv47(LIay8`B-IUTcRbE?pW)q)@XfIcaFFp_24vH=Z0fc zO^l`yy<6&IwDTdgRa-8o{xP(eOkWg%wvD->hG*3RYunLD;Ov+kKh3{Al*M0J+XHG* zy@~4(|+wJR@j=qc_Ka$n{>+`;e=Ic z|C?Ar5x6#3_S#6jU|1Ly7Z(;9-;11H71Q?kQ0*a4$)$XGWGfIG=($G7gLiz*leDb! zjL?7Mo9ouSxpBjr>({@zVeF2v_^aPhSGR-CPM3z%;-afSyK%1`UwGda`g8l{Lwo#6 z{o{;fh&W`KnkfcrOr&Kxh+3gPo^l=|$j;BS>V*E^;~D|eEuGLG^F$mLCasK>PjT8_ zm&6>xw^qYdM@8uG{LG+$V_i?0PREMo!pLH}(Q?^cou%zAyUXp$Y|ZNGb{n`51Vfv- z(2l6iqg2q~3t@y38YYC6OXF*0>xq|?yE^AX+$3~`{yHv;Jp2?yDXT@o$N8D_ zGioN{uF*EI9TY1vRhx|xLVxu|mdAz|CD{=53|+w!+hIYHu||{fWnc~iGh`unWijDN zwn*Lgg1VnAoMoX6h8ETzI|}QZqlJfrN4GfNaK0_1Vz&}3x7f&Q)x&PSd|9ij-HFL!CRng@ z>PgXu&kynyVA7M$@7hJ5_DdbgdAcvmlb$rc!S8Fkh>i&X&e7&KIt$w6RzT>w;0P6t z=@2NWpCcS=cYY`OT=G#G+UdS9PdMg+fJsc@7#I>@e&g~j?b2x-0NwWOz)W~ky;?aASI1rB0cKyQZXuwvKnF;`bPfPNqZDY+Yu0P+ zbIPF7D5b5)=X4UN^HmyRoL0_FYCY5^J&C*#KJDNF@tJdhw=31qPR{|f2W(D1hn=J0 z%4yf=KVKz3*52MO#bb^b92cuNF778FD}ZWg$7X^h>|+j`Bjr(tSOt!G5szvA71bkF z0i?QDYb(xP0~@i!C<#pPU#AuP?YKCPV}dzj0}q->#o8T$i&-umHh4|gh-2G91zRG_ zyVQZ_vBN&Rq|ufP{%E0%FSfcJ*0a4{?dT z%DJRJLmbuGO{_wSxkoux<~J@mfRm07Z$JJF=Mp`Uh5uBZEolc&xx{uB=u*pGXDh6PkRoC7lJDgrX9(Ef-PVYdDpf6miTAO1Z9d@fRIa<1N?bT!T>^ z9<;jJMAxsHvVbj{t?O8=7vKp4BgccfkW%;JJw~wTvSXCxy};E6$fi&ipmor?R@Su; zmE*XOjwc3_SW;gxA0iBN3r0{~80+}Dv4t&jwI+E!x}DLa&W*J$c`jxWox0s|^?O|= z3@AEoXg~Vz*{3yRxv?R_F4q_;+_3X*AAqd5?gO~vBDz+DuL~h_+j$TB?JjH8a&Gh( zOBzeGC?hwPYza*r?=BfQaLKzJ9p@Gg9Ju&g$Lbr$3>Yxx#?`A2*A5s^dsrIcd6Npa zkG~ zzzO!t>B8^Nsi8s`juI*}VHM$(HE1(hz14%AjlB@lOP%6dS0nHW9PaB*vf(qk{bKTE zHGkKnd%NBIVu}pw-mcp#?naf15{*sjHVWBLALM?qyI&EHyOqVb;Ob?uDx0@4>$SUj zLN!WiE} za1rqlK+&J4AGq{RcL-(!0zFHw?)5vN(G3XBLmB{;a!a`7rw0yD&@R?oK>>TUov(+v z>eB`VL^V|VE-%IbJ=Ob&vDf)1W;+Cde?x^pt-~7tKjcA^7N#dmnBZ>r447=poWj1OttW+T0oCWOL59u)GAnC!h?NG zFFw*j4!0^Z?e*978RM|EB0`g+M0{3mr*{o&E*p9bf+T|v5nVnMYSf{)+nPpT26Be< z7@XGV;PPd#+K?H&E!=Qi>;p&0U*yzrEyhRFoG5}%qc8V8iYaIWYxi`&m!y&VXPTEu zW#EVrMzF#rpQorH4(X zXH6xc z|MjNLC?ep-ooh3~9lFeegVgd^_kmXAFSjn!5rG!##!D*S3kIy4{-S906;W2MzC5%A z=N#WSMD3zGA8=*5`yRUI%(Vb`?DkbimdRh?rkg~cEb$dR1wBh^87+S8(NT;xgd}(C zDZJ0}cGQ4ht*3CvZf&6H54{_@`xYdGpmXg(G#L7cth7sg0PEhghgMe8*%VK@n)Wa> zq@l_f*#QdE%iT4ZtIq-t^jVTw!>eg`YX<7Gz0$1dDfct3Zm!2=IQL2BP>+D?M7xj#2zmk9>L9G95n+ z8Ym(jb6e&yi{cU6({wG~Nh&;iUfo|bT10O>4?9HV_4y4Ci>%uS=@!rlzN*D6d;lm$P7u z5?rzg42-zHi&Gp2!NRS+58rzn6i3slD2a*HEa}O^nEq_1X;2seOqx;-bbWr6dXXks@{q9Ac$$4K_ID(*57^+I zQ1tv+6ruIVfM$Ras~7z6!-9YPwBW*p1wRQP1~_q}aqV9Veqi^yU?QkuO2ZC@T;$9h zh&7Rw*ex*Iw9K>v(6#j%<{+~<#%9B|B1!=((xxt+x4>@W>o~HIV+iLpg@gpz^n3<( zJC(!=26K=-gmxo&EU92xj%&(yVAiu9*leOlfdop1V8)g)o)W=k&cSvyp?T7QhVaPj zMpbPb92GI{z$4kal>srK{k_8@Qli2FlVU4u(dHpD3lgnyiT%U-1+$C&Qu++9@E&+i zRC;<;Txu%YxHm4@8s2|kM1P;i(3k~|ELEG zBJ+HG^CAoGPK}Gn%#4XkRkw}y_Ztut7LyU$FF1BoRwH}ExaA$?A7RavqQirO6Juva z4;%^kxWn{Y$*=d!rIMfHfVe<=d1fxfD6jid+H4b#G&5KU{yMK7H=Y$2sK-5@XX|hf z+P{Gj12{(gbmV(a7=R#OfdxsXQ9oHL<1c2eY*P`3X9|E$INk*U@bV9QSURlvA$@{SgjZ0aqo(i zQEYFMb#mjl$$?E?HEYIkqkB&tjeC zp?b#$qgz`?SFfqAUc(;GPE5+pO-jsucI68zR=v1l#fz&}ys+|F&#( zOpF!dp+~Q5p~H>VS&idn1vYxsZWuFWL#>*l)4`~j=yheYINN!%tgfnB&2|~M8=tU% zTC_P5Ck5anrP3g5^rgcKLNE+d_~`{^41f}`HxC>J!}SwZAM?Mr_N}*S@AiLS^@Qsi zCb?@etwQK+h}F#>j-Z07QH0({W#nB z0~03fZ$z~j6B1a4Flg|ZCv*hFv%zYE^kQbZpuUwnD}Tc7y1LyHfJ8(HOOr&=qTb@d zhM9H)n|MyQsg$}sP_S8X+!fY=>U|uGF!!Ea)Yg2cHku8obBU*CEL^=aBi0Gwk0ji55I!gya6+ba}qGk{LqTtfD@sdWT9!^w(^0t!Kp3NS2XV$ z0CmH06rAv!^;=GYE(m5SodkDTuav_tuN)KrT#a0<>y#nLwfO@$P;>bP3)oO=49 zXQVqX-!8V&Y>O{@Ub+jim5ygj?ByWJ0_V&2@o#>nA!0Orq6%TqiO4y3FT3T1$#>m2 zaZc)_2iWq9v$quHubKN-BnNwINd`SA(p*;U6^<^1`gdiG%EA#gO`Z(#empU1c21>jbkdmlvm0{jKkw*JKfmuj7SYkcBJTUaW^0M=zjn{H8xo_Z#Si_%sddL1_wN37 z|GsZ`?fQ1#{%?1~N1e<*lInnOKU1_Rm7h`JUP}(%772X+h9)?iujav|nnL1i(DD8u zm@ubPK!m2#`{Y~_xt8ge-g6BcMQx#7EV)`Fpe_* zo5I0IYn+JOTyZ$YEspYG#aSt8f|!uiD$R*p6UYRnOxn6s5t-n>wEw&7UliV%-6&6U zoM&g#XAE{eA&f|$k*=l-w>VpcTNXLb3WFhYTg6$T56*q@qkMg6scy!^gKo-_`NxJs zlP4c)7<*{SltW`v$7W@XO&vaOp8P@e?$*{l)gyM#yk=MR%7Np`%Eu>9y=Hm~mxKe- za-MyUuRULh^%d;ub#UJ1iyuvL#Iol$o?W-@?8c2}*RFYeW7GAGjn_Ag-`Cil~5 z{9@hf8#cbacJ1pMH@v=XcjLbCt|EvU^u@0CyNnD2h#1`E$`l|7K3zG&oysWSrpF$5 zjQP&PhYu^GoO!~Foe$DGY4PL8z4}LRCXsT^Xo-%NBi#FS~m$t0K*l-1U{TS6+kcVKJH% zU@r+yr=rf8rTG>%Y-&(0`^F$gd(M$rJ736}p7-_h9bfMV4chqklc(ni zjcG^aHJjeqpq_VLNXeQtap}>OuWe$E4ex9k-Jk}rZxS=max6fn&m}{wW^1uny!5$OE?P%W2&s6)}z9s zN7ciZ=gqr}=InYKRw@ZnBx3hM97<7Ue(uxg9nFT-Qg*9;iV*B8xE@d}Y${Mc$-8ml zo(F4Nez)V~Y@dV2zT38U$ilj&Yf}cU7ymk!4W6rRt*PJf^F6m;+PiJO{6f&>8()2U z=gEn4N}LypM$j5b(}V|4V&D6;9-Z8J&o%XXn&b^H zuNb}ai8)(7*yY3CRNFrm(*DM#37c@v!}NP*OuTt!-(7w8yuW$Q6FWz*dUaEO*77$Y z?PK+J@>Y`Jtt{vM2F$b0Gv?x1smojW0e;EbdO5={Y1I7^%DMF#vffgLDXc!B%u-l@ zGI)lXrDh?AqH0;f4yX$#2b~=)w3fF}psTh#S8buL+Nhk?k{;#s_VaVKDLgeu9~_KmI4;>k zuqiW(-$4RPbBybo>q`uVKuE>SpJ)78_+l{x1prwrB7Ovqzy@Le7^B>gkj+G#1lYO&dR?%$d6x8BAA-(1Q2HsSt) z4Ha*RA?mB|u#kZKO+r`pZJ{>*`UB3*)w_%1az>vLvxVw=n*9RB(11|kt%?oow7O5U z_G`YUT2Ma=O9?31Ibz1|SYzRVdVgE!sChJ2h+r>^Z}8p}>KZGQXnhhAUXMO>qkh-u z+0$HoZKX>h>(LYTbBPRf^~p+CxoIBdUY5396<%MDa!t~GJ>ZqP;EnSr_dM{Uagw{< zW>-01qa6CPF(Qg}QK^rJz=JsO;2DmU`);g@2S^;RkEY^!J_{}XM%PQy$MUW4p)wJR z$82kmn1EP?EaM1~1Stsp*#2majj%X3g34>t0*C z_BHv|Pu1oR7PKvT^Yz7Ti_fXEzWI(F`Sbj?MQ^-2uWjCk?5@t!6OO*-dUE+|M<*;< zb9Nn$-9gUdb!XS0#k;_ZmpCtyT+~j}bu?!4p(|T3zLoeqDNPM9dJ`H2@6PW9Mcpo3 zlycR<&LhHXY&LyBZDPkz)&w7ea#1Sqvjer9s4;j7dHN|wBRs4e+L9%D=B0F=S05Co zXxS-|PxxV0d(54nl2Vg8y}zc6j$b$2DL<=jcfKmXl@PjGOhe>axePun^5ns%)v`e9 zKAg$LrXFmLm`D|CuGatFkp4$0)x-FHZ+P_kNV7@!m z3m(O=-A+)y((Cg!Ar|DS4<`s*QI+FvXA`Cwm;FLj!VY0euN7%@odI3Eo@&8Jzv)?x z7>)G~O^&-cMW$Y>ac*#~`XzcKQ)Jht(gEo;_=P@bEAlN_jOA%~T_Ak$ym{P#mKe znWLs6ThvC=VGo|^ZA2sWAae9*U_~PjiapYAoFc`4_q^ZZx7g!%Pk24=#~9_gtZ3EZ z=nOfMi^s$C&Y}}Q2!MY`Xuo-Y zA^m`arm?)qK0+E&1YL~B)hFEFh1=ZU)eiS}*5Lkrwd=e@h`;KfYS~x*A!u7fe<^CD z`8)M7bXW%Cc}w%zLAHjas`J$CSSoyyZB^I9ZyvZ)I=5>Nbi@7Xza+E#1foro0pa%) zZGzWyf0qSUUqkQaGmu!}OT!leO5>9Ikwy0*wf#2rE#b0Lp_lkFQUW_Vi>2qB_Fe49 zUDR*CG}R%Wb}DvbAdbaPl;eIel!LKr8jV6trAq?;VMf>hfhx_NMwc+6puE>ps6@LE zV-%qaVr5OPy{5+QjHLJ68ts?xiS}##uw}z5Dcf+RGgA8;zPzGhxqeOfM8CFdn3U>_ z?*`yQ&tI-$ZgBBef+M<5nyL?MH}6Hp~v0IZg;Vh7#@iG*?QOA0j`lzvx~cKzbMJ@PfS!! z^JCoQdh@fW+%~;7qqW?8cKc7SBZA?SS4x%Qmy*6x5B;|{Y*x8i$vsY6*7XnZlDt~- z6Awx)@^p$Ro3`WH*Yb2+JK(x@(Z$u7F21?B`o7DPSnRrMcoL$izU#bnS>B3~afTi# zq<(CsM573)xQ?ji0ZuK9s?DS50ZuL2Nl^+xn0>VI*6nPWtsrD~Y(v(+)|{<<>%iLQ z79QGCGJeq5TNX~5GhleplBEmw&uVL5zu=Z)dF$xkj9+vA81=T=hi0d&J=5^Fy3@^V z6YpDi?a8|0ISVQp_tr04T$?_osi<^I{lr%1&XVh=EZ$jPO}fs&Is&l^E%vNoZMJE# z5(>xu8f=BAw~`q06aONGEV+&~W6PG7VFJh!N4(rZU_SeSwszf~lJTBZx)n zlE-MdN=4MxSHu*cg0UNzjI)dq6UDcOkBl~(`{hj@K6P={!*>+Ut@cTb50A5&M?H6Z zOUE_IbI=d-e>gy|i;1 z9Ky3zw;x7}9UbYD1^jLkPq63cON6h+T?#w>06O}P2~`?vh|w?ffl zYfqe5`xup6$h^c-MkfOC`EapRO=H{FuQv&Raf4VYh+H%Ado)Lm`-6}LeUKn-*zo-Z zO3pF5^a^A9oqX8wWoeBj?rSU5lNoUjlZ)P$?gSO{Nwmi-S+ zZb&!(>S>U!F6T-0Tk$?+mo!`|F~LJ9f%b5o!pSwOl&QD|`=DJ@Mi5B{E~ipscRJbhrCa>B6tQdM2si!Lf8i9 zh%k0x+7T(^h-8trbZ$6uMEt?wEAPAXv{Ftl=g-l7R87n(6sq_lG3M0-TL4;B4$<=#imd66%c< zLV|EGgg=6zh&9s`w}NO$PNYD+kI#|dNNfr}Cu-UcBbgvdPOrXF*Kv2ns>invt~s)4 zbm@xQCSTXM^FZs0J2sR)^i17dYpyF_I(+A)v2#W(z&?es&WJ(6KxdJ1hx(xr>C;tIDhO=Q~!j_m?uokVK*Jc35?}@%s?%H7__!pm^wt9zuLsl!S)()EHWHC?<`V%*te?nRyCA;C7lD2&Tk%PkFgV5)V_P@h>kt% zN0Z=)>-~Jri^I)NUK}pE&gcAj=`Woe{o`SuHtprPlE)-EpXn+UX3KQqt(nUtMy(>f z>@3LUd`7Cy?>rSk?I6ep8%vh9TH-l<=tTEAoE;sJV1JU zy$W>CicHcE1K_!w#Mp#RKh{n(>VA%kjAdU8^I(`C;A;b@W1KJ4&vp?eI`1~lc9Eaz z^U;rG{x=3rqeG5xu&VTS&%<6u96BTpb<7Ztb{-mSr!!gYqtUXhCNHT8=ME^8b*Mau zIvGO2BF=!}o+iUVJtOGYQ^$ky&_@H=*IBAR8+lOuK)rAy%T(n8lA05A8tP+0V26<4 zy!7w`JJn@N*dyx1*=*;|`yVxl7egV7dAyFkCTw*q)obBZv4rlGb+&1>ncpx3)H&zh z*W1@ExG(jB0(9~yXsucDK54kJ#n8!@7&PlpT&q+zljhYl_4&uUMw#B@S2vL!rmLXg zW6Y;5k?#Ya`eOXjg9Z`3*Rj%ZNi;j=$Ulom!R0=VpFTS*vq#l9HRgm+*dYvYp6PHt z`vm(d`-qLdv=@n|VP6Z>v*H{7UA>4A0X5n`en~Ihxz?>0o$p0DAEFlh?`y@z7u6fI zrpJPeiw&SA&x4xE|1&+W(*vSN-HX3OmZ!RRk!3#gAJqG93NhX4HUWCiNi{UA(Q`aB ztkG>g^w6)ap29xz(62@hA#L54pKR24p~Q`m=bOjGadm>8u0iS&o+|-sYI@Xcce4d2By8&daj%bcgfzLRp9N1@;;3SnTR@ zOgBxCm;~=f*{Q*TKNAe?c`L3}D!bgh%CX(#FV^F<5I^Nk2>xd@%7R`fgI>5>vPq|Z zo(*5eCjFrcGp6v3?s6U@-{`_;czfCbK*)c3@VN`f(_p&EwDVeyr?6OV|8|#;T<>DoCL|%5uox5X)E+2zqn6=ZF`FYHtGd69_9X2Z7(m9D% zH0i6G(2B>=wrg+>#~^rwIP(>x6p0`cuOcxd$QM&{X^3C?;sw9Z^HdIJL2O&@z~X|+ zX%)j-DhrAS4lKwU-ddG4Jg=nLxPrSa!>V`B4wR1fJgwuW@~KG$1xfUZ%N`sf+#$zj zq(!C_7pKsrF$*$<_$$xvaBOC0#EoJM*3DqQ04=$qrZGM}n#k2uqS<{yb$V^xjLIun zo;GsK>>B+%Yf;n>t_IUQ8L0i7ZW4Z;VDgvdfnSp_n+aL!$s~hW#wVC&@6J?%x%7!q zgUxl!iQt`7IAr*=%FK$PB@-%!O&eZNl0^J%8CKC!Sy+;kjPFy2d0r>ZULQMq$iSk) z;nRj`t&mibU!^^P7U9<`rlED__T+y(=lZ=;d}^wT>+v}`@wOpD6FpjCxVxE*<}yBo zO;T3C)+R5jN&h+kFg*D_| zU7Z~`JGW8Z4o&pe&g-Co6zQ)o;X0cy7Kr6?q{7c;6+Xt5h2r1EQfVfxti~9PuFMyg z#9O*QC1#OO9^X*Kf`U|VHPhr-LYTJ#%mj@20 z+YTIH>$Fd)fLsRdHi%u{bc2umIXYxO45Xbk*gO8$!v+NHNze$a*fjY*=<4IT-j~$d zyFsFz4<4{+B*Xm06OK`M-R_B%2R70b)be-&*w3@P5e(_HW0dnF$0)_dVLWvR|Ac?I z=n=Zn!%r1s1|`DD!@^UC#EqQrZZtfi(;)Vsf!9uJos62t8kKrfiQT>6p>P+tQK_7e z9yVYJeY^3a8#gcyG|zbmub!-hoOnQc+yzbO22Fznyf_@dNP;`A(S^wPH|h;8iP72< z`&iMI&MKU4al^rb=739l#_t<8S2``O*5WosyX$RkG&qE?3*}&odX^JkapZ`vc$70; z@`T4vCPn*S>RHa*SpeO08oI}jXzknzH-D(L@q(7NyU)c!_k#mxV@Qfs(0N)akZT-I zi{*}|9Y0)gbd^;2u6oBhc1o>U$EF$x3ci}`_i}obx`AzJb0({SZEOpyde=7|_<8L9 z=#CFknW1ZRCb4gM{p&+>(`L?_H#03abp04vE^q`D97L3wL-Q4yc8hp>$wp73ZZ1Mb&X zw1)@BTpFr7zXEZpR)z4C`XlFx=h0=qz#X_&-K3FLenDsC#E`}Td>Zq6n6}c+_0m?j zuG3U*ht{)K)Et!`o#uIf7y9BMA;iUZy#?~z=Xaq;xwwM}99b8t3!!4#na6k!WDjYr z>v1mFpdzS*6r&xlirMN~?Qu5?-FUcLgY1CT8n9(gYPy?ruzsyl`7c8UYbC|~7(onIo;FH4 zhPj@8%DBd{qjHtX@7+(EesaNl#(mYJ_GdkxCk=_`pX**yul)~3Nsro}H?Dcqe%k%C zN9`{dS9!E-t57cYgD$qXqGc2*qx5)sw5)*QWci&pvLqfO6TjM_hTR$MTy*FV#(z(D zZN>PnA2{-sR=-JfEYah$+KE@tFwiQA@qF|_v(UjIeB%qvGV2TS`4VQEHu*#Tq(mm0 z%&sIjvyuhtcj|-ZpE`a`&AO4rH*KAJa^Z@P?>PL^_*s=tZm2)doV|7Bb!X-+eremR z#~wa&ffaS$bM)v@QSMMzzRvviys)WyK)&piIpTq)k?Tj6904_pKuz`LeNU>Y zdecwB_d(9bzht%F-M4n;DbT^z5~fqD3{2~47MJA{J>x4Ab$Yzx$LxIja0k2jr268u zPpz$v>!T!gqXeT=Es{d^b_9Bhjum#K`~vPYbw#@&JewuNXi2p%;g;pItOdIfe45y$UFxnEYa-F3#-MnigMD;Cy=uNpA#?!~`w@AHcB<%33LA z3FSkYGVJ-An-QgpgE#dT-J9xW8AaVfihpq|5%)Tl+@^gPM$vHIF`oE&X%84$CQ1Ey z@|`?iu;Z2D?;MpDe@B&g%29<+{<|k&R|U-U0rq0uEk*LV1bq{YEj!U>!*V9-wul>J z@d%D6zk5n^Rghm^MnzijqUvdj_s@y5L+*SjrQ+l;H-dCcD2&TO1o)K!pV>oP*uJ&cJ^*oy0t&mxLww z>>Y~xuzSP_Vjp>$q9~teztsz3ACrpc(I?ntKOSnAvDc&o;Urd^Qyu^w9ygogwB13% z$kbwMbbV`qHKI)ZpfD}0VA#XoTL(p?6%y<~z`g~$$ZX0dT?;YRGoz0E_+)H^JYH;- z--Bl5_DO7Yej$X*<2TVg9V33vnkBM(9(d|=aRQ~EA(#=ezj#poQc{!)9N)i6j|gwe zx8wKE!VP%3O*V<83atdeenxWwJIQwDs8f`@kDDLB-IcgIO1~Q-+k~#s>Xd9HZ{GvW z1lub8M!Z$Qs8zX)6O^!6MmmmI-JeVfhlOpS3BrEXx7yiR!~Enwy*IACecXG5vA?tn z0ti6s<8Z#BlE+m=H&ykHBy_HtBAl%HQj*U0dj(Pmtw~6E`czw zk^UmilqXAy*+g70bx41a6nV12UrC|0bkbioX;hvEmDj<3UN&r97obR$!dLPI$*lZf z8lY?i%I3 zhwyuX(fXK?58+(YIvXZzXyqdBc=*nKlTlQZky>2L7N!*yrKJ}a%l-vv>4k;qX$8h7 z+T$-c*!NAvo6qihO!^3o_KFI7Zh5)lU6GkJY*F=|izVN#Gb`rbd+2dChe3 z$?Lzt-CvL^lK{Em9LKX}U~LT%?RYWk(Hoxs;Nb)B%Y)d&;p(X@HgS~tBwz(dUyHXZ zDO{Rt30YX?%cj>dzs0O?%_ZsU`tQE0f4oO2UFPa*xXjgFR8ktg{kGu=luDJp5jQJA zy~!?*m$W_oIXIyfm>5(d~N0zB^;!smGUqOp?efBJ@Ie~PL7S;QnaR21GfThUaP`qKlJYYNK7r-X-0^Yc%jdJd{NVjQxK0OuL7lC)e9xS9=> zoGW^T&zhS!xG3755D+=kwq(obdkPCvM_0zBW|_^~70Z(P;VWAJ$00g}7v-fK-w@Fz zq~0`ls=PEny~US$rrx*EtAF6SEnG2)2b6Q@lNX@5|A`VGDn7y+=(lF&XSxE23*|4x zB69?XNc!$Iwm3^|HAj5Vd^hgS#ocmqpjIFB-On}ZxKwlCzFWDz3y?n*Z!xa`w97iQ z0Qq0y?dAcV8t(w>JHpvHlKGhjxHVpY{5i_`chh(yxb%(eH2aTx@4az%p!Rh6TXC!M zQ*YAOShJaHyvpI4#*@D-m=+)aw>c znmVZ=pkGsH8a?%A>6q}IGDfQdEuQe`*44_GXmvG2iLuwkKM8-6x47w}OOoU7xSp2h-H*LR`*u~jQ}L+7QYmz1zSWE2;Z0yM|Ps}BcC z#c8P}C8=q}#wV9G>8S9EG7{W`tSRr4^hvkkN{xQyPr&YTlzB}V>0$S=L6!G^p)RdB z)S5T5wV!XXGO{o&BE8=~-iyl&huw$fD8}xksY(Ix4glY+X3^H&Qi!Ihi+B8%ti?66 z@&iMQl}vSR6x%b{(`XQ!imSjeu;6f>049O?v#udbTyTKT*XO$7GuDLN8;*gGKyZGWTB70O2Yfi3I}6jp!Jl(+gTvA} ze*z$tcPmd|1~Lx(;n|1aGIETpy=z3-R#=>#Q4}1XG&5V*jj?Sb>@~V>oG)!&mrzI+ zE~L0@IIHK1a`<#ZQ3|ZDv=uhxlwPCWh`dg-z4sdLpJ9s+E=o@?DXQ+h#;wE4ibK;1 z3)2b{-|JDI$RZ%Q2b6EQoz|>}OHw_h)@n5;i19Gc=@3r!5J@P+xB2gt>IL~3Lt2eb zmZpAIcG2h;H~b3d@bK7f4ivt?OMpz(c+FNXRQ3ja=EXAfxghC1@jm58jycUhdH5Bc zK8DyU*VqA~g?k><72$^L>eZAYgn0&*xm1 zy#-zIsje%~r-YkEY`I?EqRtCqJ5XBpKv4P%ZaZ|%0!@gx*A?1KHZ^obdezF`nbxrd z47+yOgNTk{2&hl0xfZ}@W>7?e{>XS@u9Qrkjb`H#p$W)#^J|nwfEz;^5@*^oFdPCf zR8Al6w`>%~6f3`h4>Jzi?c?JjaH(kj1L)hV}WAZa&5Bu0sA5{ zH&Vze^R+~TStQ9Kcn3;MObqbLO^Jw5vdaQ3zD=#sJ{`)Yv44EBFd)m%V$Dkp@`}h$ zH6ukwd4NTU6|D84KIw(QqvfRZ*ub!cCBp)nXO1$*EpH1PP#Tsrbk>BXYeE#k9wu1J z1I$_ZDZz@jccL5>;nk+JmbTw>1aX4e0AF9lTVy@~g9Z$+9+=UxC*RT}?K&8n>?2A2 z1BWCB1cyc^_PbdMnzDRR;^1&^ucU!Br>cC!$i70%j$z}kpIhq98Y5aVi-f_&LAgS9 zb&O!m_R3Y#heel7+G`#-bwd0g@0l!2@d>g=<%pxb{Ra3ZRS%4B6JL$nTvNVxT10$= z95SjU!WvO$ODW7B=#^Vw&B*lk9x;BHg2k2o>G2lD%a-h8tC>|BGr>0?TVZDF(7deW zV~2>$Hz+ZvU%YR>#JaHAzM~h!uIg91X($VcxB2zUom$a1%pU4Hc=_z85s!NLh~CLN zYwf9)z|tVUOkW{d@DB1CIx8})q9Uw+T3UZ=AIw-j|z`7`lZ({!h zYhX!Pu;ObQ5R@K}EilFsg9KYaa$oOgF{NxotTLc-s22+e3lgoV@sgMjo^5~Vo8KiO-QlAOC@?igP`t9N#MM6q9pSFm4Daj-QiG9WxR zKBgg4X!9PK86MS7v`BtQwt%#7>(D{r-j;-<0sZ_^3c`hu1aFH^Y(>j>>r z5b)wqX`68nU9;P`VuNPHb*?xlJjk)M+e7RCKs9hvZ?}OcIfIA_&a~Tda1WX+(+og> ziVxhjLA!A(0IFEX0O|CM4b_p$X%}XDm(IO@{IDG{Lf=Tyr|MMAz$7p4@WF|TmQM+i zZtj;D9U2^vJS4EcB>5!A9^550S@QR^%s5~jFkn!C4->r=U*CY*ay>_I+C7@O%mD1O4!fo4%@ ziyv5>PYbXm`AHVBUsQPJNbfcw zvmquvH#{IR${Ji8-^WV5ntFHStf5{(-steYnSMc~ftFNz?apLx z(Z}m4A1^OuI=YNxi5nDTsgS(9EU}7LO6Y?b-a~W!BEkj_6SIB2%j-keBndGIl7a~y zFZm1hnB}Z=04vI9zgHY~{)-l%ho6NLFKJA%0$Q!Ux^~7B4?bc(5?LPoP(T zGALk*k0mOsO_mj#pMOrEXwH=L(tH)cD^c|EU)#qE9)ytACrYt|B{1i2EoLV9_{66Q zA`?aC-QUM*@^yaD6{(!_^k>*9_8fbOy~X~*zF_}imjxNzKwtYG59j|45624E4!Reb zScXKRVGUyZQb@io>P3=2BAQT@-xe)8;h{NhK7#hs$qH+ej8uDV`k+Kuv`|9H^}mUU)IdV z7fTmaK2Ww>C|9QyL23V`*lg(xoi2~KY}*;xw4#zdqXso?p4O1k8e2STvYO1kTDEtl zxLUn%4cntGy@ujN)m^tB?o^Al)fn^Qe1aHr42E@D1}L~}c$v4o zd{*?^{;E>zoV@;@ZuQSbqJbcPrstucJ=YZXV0;j1=U%7{`8-+Cl(gE& z$oTlk$l5gFyYxEkdtLgZ-Ajfn*?r^6(3PwtJHeS8pOqCaoJ+`73kxPpC@5@f+=1O^ z%kbEkbmxa2AmY=<00cX`WcThR>R|TXiWTZWr_7%Yrg!zl@kNETic(uxG(PtdB9JDN z^O*P*+DxF;=uG^|5el}~(h_ifPdb8ou$cv^hNF-R+f8N!DVc|GGi zCOwQDca`Q0_l%M$)O9t}xQdu!y4)8rVawHH!oiJtOn8gjH@kI2SgGA!8aASpBC>-N QFL9GuLcBM-OEo$E7bYrfRsaA1 literal 0 HcmV?d00001 diff --git a/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Regular.woff2 b/src/core/server/core_app/assets/fonts/fira_code/static/FiraCode-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f28816fbdc4d0cbd9797094115a921abf663c377 GIT binary patch literal 70700 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 z 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

); + expect( + getByTestId('savedObjectsTableRowTitle').querySelector( + '[href="/app/indexPatterns/patterns/1"]' + ) + ).toBeInTheDocument(); + }); }); diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx index fdfd2cea2c28..6642dd61bd0f 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/table.tsx @@ -250,15 +250,19 @@ export class Table extends PureComponent { if (!canGoInApp) { return {title || getDefaultTitle(object)}; } - let inAppUrl = basePath.prepend(path); + let finalPath = path; + if (this.props.useUpdatedUX && finalPath) { + finalPath = finalPath.replace(/^\/app\/management\/opensearch-dashboards/, '/app'); + } + let inAppUrl = basePath.prepend(finalPath); if (object.workspaces?.length) { if (currentWorkspaceId) { - inAppUrl = formatUrlWithWorkspaceId(path, currentWorkspaceId, basePath); + inAppUrl = formatUrlWithWorkspaceId(finalPath, currentWorkspaceId, basePath); } else { // find first workspace user have permission const workspaceId = object.workspaces.find((wsId) => visibleWsIds.includes(wsId)); if (workspaceId) { - inAppUrl = formatUrlWithWorkspaceId(path, workspaceId, basePath); + inAppUrl = formatUrlWithWorkspaceId(finalPath, workspaceId, basePath); } } } diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx index 348e20fb257d..191720256024 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx @@ -832,6 +832,7 @@ export class SavedObjectsTable extends Component ); } diff --git a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx index f526f7f6c751..e83ae7cab3dc 100644 --- a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx +++ b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx @@ -109,9 +109,13 @@ const SavedObjectsTablePage = ({ perPageConfig={itemsPerPage} goInspectObject={(savedObject) => { const { editUrl } = savedObject.meta; - if (editUrl) { + let finalEditUrl = editUrl; + if (useUpdatedUX && finalEditUrl) { + finalEditUrl = finalEditUrl.replace(/^\/management\/opensearch-dashboards/, ''); + } + if (finalEditUrl) { return coreStart.application.navigateToUrl( - coreStart.http.basePath.prepend(`/app${editUrl}`) + coreStart.http.basePath.prepend(`/app${finalEditUrl}`) ); } }} diff --git a/src/plugins/workspace/public/services/use_case_service.ts b/src/plugins/workspace/public/services/use_case_service.ts index ec0e973b6dac..ae127f08a5f2 100644 --- a/src/plugins/workspace/public/services/use_case_service.ts +++ b/src/plugins/workspace/public/services/use_case_service.ts @@ -61,7 +61,7 @@ export class UseCaseService { if (navGroupInfo) { setupDeps.chrome.navGroup.addNavLinksToGroup(navGroupInfo, [ { - id: 'dataSources_core', + id: 'dataSources', category: DEFAULT_APP_CATEGORIES.manageWorkspace, order: 100, }, From ac5ed85f7522ad98611d017c36225e35f5c8b2ce Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:04:17 +0800 Subject: [PATCH 236/276] [Workspace] feat: Add workspace navigation for default route (#7785) (#7824) * add workspace navigation * Changeset file for PR #7785 created/updated * optimize the code * optimize the code * optimize the test code and add newHomePage check * delete useless code --------- (cherry picked from commit e1e81698bc73e95acb86c0143b2715853e0ce054) Signed-off-by: yubonluo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7785.yml | 2 + src/plugins/workspace/common/constants.ts | 2 + .../workspace_detail_panel.tsx | 7 +- src/plugins/workspace/public/plugin.test.ts | 22 ++- src/plugins/workspace/public/plugin.ts | 28 ++++ src/plugins/workspace/server/plugin.test.ts | 145 +++++++++++++++++- src/plugins/workspace/server/plugin.ts | 44 +++++- 7 files changed, 231 insertions(+), 19 deletions(-) create mode 100644 changelogs/fragments/7785.yml diff --git a/changelogs/fragments/7785.yml b/changelogs/fragments/7785.yml new file mode 100644 index 000000000000..219d33e5d831 --- /dev/null +++ b/changelogs/fragments/7785.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace] Add workspace navigation for default route ([#7785](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7785)) \ No newline at end of file diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index c8582d2439de..88f9a5dd9ff4 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -11,6 +11,8 @@ export const WORKSPACE_CREATE_APP_ID = 'workspace_create'; export const WORKSPACE_LIST_APP_ID = 'workspace_list'; export const WORKSPACE_DETAIL_APP_ID = 'workspace_detail'; export const WORKSPACE_INITIAL_APP_ID = 'workspace_initial'; +export const WORKSPACE_NAVIGATION_APP_ID = 'workspace_navigation'; + /** * Since every workspace always have overview and update page, these features will be selected by default * and can't be changed in the workspace form feature selector diff --git a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx index 6ada5490c379..833581f0f54c 100644 --- a/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/workspace_detail_panel.tsx @@ -45,11 +45,8 @@ const overview = i18n.translate('workspace.detail.overview', { }); function getOwners(currentWorkspace: WorkspaceAttributeWithPermission) { - if (currentWorkspace.permissions) { - const { groups = [], users = [] } = currentWorkspace.permissions.write; - return [...groups, ...users]; - } - return []; + const { groups = [], users = [] } = currentWorkspace?.permissions?.write || {}; + return [...groups, ...users]; } interface WorkspaceDetailPanelProps { diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 41f779911876..f3a5f48f33e8 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -22,6 +22,9 @@ import { workspaceClientMock, WorkspaceClientMock } from './workspace_client.moc import { WorkspacePlugin, WorkspacePluginStartDeps } from './plugin'; import { contentManagementPluginMocks } from '../../content_management/public'; +// Expect 6 app registrations: create, fatal error, detail, initial, navigation, and list apps. +const registrationAppNumber = 6; + describe('Workspace plugin', () => { const mockDependencies: WorkspacePluginStartDeps = { contentManagement: contentManagementPluginMocks.createStartContract(), @@ -40,7 +43,7 @@ describe('Workspace plugin', () => { savedObjectsManagement: savedObjectManagementSetupMock, management: managementPluginMock.createSetupContract(), }); - expect(setupMock.application.register).toBeCalledTimes(5); + expect(setupMock.application.register).toBeCalledTimes(registrationAppNumber); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(savedObjectManagementSetupMock.columns.register).toBeCalledTimes(1); }); @@ -53,7 +56,7 @@ describe('Workspace plugin', () => { workspacePlugin.start(coreStart, mockDependencies); coreStart.workspaces.currentWorkspaceId$.next('foo'); expect(coreStart.savedObjects.client.setCurrentWorkspace).toHaveBeenCalledWith('foo'); - expect(setupMock.application.register).toBeCalledTimes(5); + expect(setupMock.application.register).toBeCalledTimes(registrationAppNumber); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(workspaceClientMock.enterWorkspace).toBeCalledTimes(0); }); @@ -90,7 +93,7 @@ describe('Workspace plugin', () => { await workspacePlugin.setup(setupMock, { management: managementPluginMock.createSetupContract(), }); - expect(setupMock.application.register).toBeCalledTimes(5); + expect(setupMock.application.register).toBeCalledTimes(registrationAppNumber); expect(WorkspaceClientMock).toBeCalledTimes(1); expect(workspaceClientMock.enterWorkspace).toBeCalledWith('workspaceId'); expect(setupMock.getStartServices).toBeCalledTimes(2); @@ -215,6 +218,19 @@ describe('Workspace plugin', () => { ); }); + it('#setup should register workspace navigation with a visible application', async () => { + const setupMock = coreMock.createSetup(); + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, {}); + + expect(setupMock.application.register).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'workspace_navigation', + navLinkStatus: AppNavLinkStatus.hidden, + }) + ); + }); + it('#start add workspace detail page to breadcrumbs when start', async () => { const startMock = coreMock.createStart(); const workspaceObject = { diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index d3c94f992360..a404132bc990 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -31,6 +31,7 @@ import { WORKSPACE_LIST_APP_ID, WORKSPACE_USE_CASES, WORKSPACE_INITIAL_APP_ID, + WORKSPACE_NAVIGATION_APP_ID, } from '../common/constants'; import { getWorkspaceIdFromUrl } from '../../../core/public/utils'; import { Services, WorkspaceUseCase } from './types'; @@ -45,6 +46,7 @@ import { enrichBreadcrumbsWithWorkspace, filterWorkspaceConfigurableApps, getFirstUseCaseOfFeatureConfigs, + getUseCaseUrl, isAppAccessibleInWorkspace, isNavGroupInFeatureConfigs, } from './utils'; @@ -374,6 +376,32 @@ export class WorkspacePlugin workspaceAvailability: WorkspaceAvailability.outsideWorkspace, }); + const registeredUseCases$ = this.registeredUseCases$; + // register workspace navigation + core.application.register({ + id: WORKSPACE_NAVIGATION_APP_ID, + title: '', + chromeless: true, + navLinkStatus: AppNavLinkStatus.hidden, + async mount() { + const [coreStart] = await core.getStartServices(); + const { application, http, workspaces } = coreStart; + const workspace = workspaces.currentWorkspace$.getValue(); + if (workspace) { + const availableUseCases = registeredUseCases$.getValue(); + const currentUseCase = availableUseCases.find( + (useCase) => useCase.id === getFirstUseCaseOfFeatureConfigs(workspace?.features ?? []) + ); + const useCaseUrl = getUseCaseUrl(currentUseCase, workspace, application, http); + application.navigateToUrl(useCaseUrl); + } else { + application.navigateToApp('home'); + } + return () => {}; + }, + workspaceAvailability: WorkspaceAvailability.insideWorkspace, + }); + // workspace list core.application.register({ id: WORKSPACE_LIST_APP_ID, diff --git a/src/plugins/workspace/server/plugin.test.ts b/src/plugins/workspace/server/plugin.test.ts index d5aad60ac88d..b71532e36273 100644 --- a/src/plugins/workspace/server/plugin.test.ts +++ b/src/plugins/workspace/server/plugin.test.ts @@ -4,13 +4,17 @@ */ import { OnPostAuthHandler, OnPreRoutingHandler } from 'src/core/server'; -import { coreMock, httpServerMock } from '../../../core/server/mocks'; +import { coreMock, httpServerMock, uiSettingsServiceMock } from '../../../core/server/mocks'; import { WorkspacePlugin } from './plugin'; import { getWorkspaceState, updateWorkspaceState } from '../../../core/server/utils'; import * as utilsExports from './utils'; import { SavedObjectsPermissionControl } from './permission_control/client'; describe('Workspace server plugin', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('#setup', async () => { let value; const capabilities = {} as any; @@ -178,6 +182,24 @@ describe('Workspace server plugin', () => { describe('#setUpRedirectPage', () => { const setupMock = coreMock.createSetup(); + const uiSettingsMock = uiSettingsServiceMock.createClient(); + setupMock.getStartServices.mockResolvedValue([ + { + ...coreMock.createStart(), + uiSettings: { + asScopedToClient: () => ({ + ...uiSettingsMock, + get: jest.fn().mockImplementation((key) => { + if (key === 'home:useNewHomePage') { + return Promise.resolve(true); + } + }), + }), + }, + }, + {}, + {}, + ]); const initializerContextConfigMock = coreMock.createPluginInitializerContext({ enabled: true, permission: { @@ -192,7 +214,18 @@ describe('Workspace server plugin', () => { const workspacePlugin = new WorkspacePlugin(initializerContextConfigMock); const response = httpServerMock.createResponseFactory(); - it('with / request path', async () => { + it('without / request path', async () => { + const request = httpServerMock.createOpenSearchDashboardsRequest({ + path: '/foo', + }); + await workspacePlugin.setup(setupMock); + const toolKitMock = httpServerMock.createToolkit(); + + await registerOnPostAuthFn(request, response, toolKitMock); + expect(toolKitMock.next).toBeCalledTimes(1); + }); + + it('with / request path and no workspaces', async () => { const request = httpServerMock.createOpenSearchDashboardsRequest({ path: '/', }); @@ -205,29 +238,125 @@ describe('Workspace server plugin', () => { }); }); - it('without / request path', async () => { + it('with / request path and one workspace', async () => { const request = httpServerMock.createOpenSearchDashboardsRequest({ - path: '/foo', + path: '/', + }); + const workspaceSetup = await workspacePlugin.setup(setupMock); + const client = workspaceSetup.client; + jest.spyOn(client, 'list').mockResolvedValue({ + success: true, + result: { + total: 1, + per_page: 100, + page: 1, + workspaces: [{ id: 'workspace-1', name: 'workspace-1' }], + }, }); - await workspacePlugin.setup(setupMock); const toolKitMock = httpServerMock.createToolkit(); await registerOnPostAuthFn(request, response, toolKitMock); - expect(toolKitMock.next).toBeCalledTimes(1); + expect(response.redirected).toBeCalledWith({ + headers: { + location: '/mock-server-basepath/w/workspace-1/app/workspace_navigation', + }, + }); + }); + + it('with / request path and more than one workspaces', async () => { + const request = httpServerMock.createOpenSearchDashboardsRequest({ + path: '/', + }); + const workspaceSetup = await workspacePlugin.setup(setupMock); + const client = workspaceSetup.client; + jest.spyOn(client, 'list').mockResolvedValue({ + success: true, + result: { + total: 2, + per_page: 100, + page: 1, + workspaces: [ + { id: 'workspace-1', name: 'workspace-1' }, + { id: 'workspace-2', name: 'workspace-2' }, + ], + }, + }); + const toolKitMock = httpServerMock.createToolkit(); + + await registerOnPostAuthFn(request, response, toolKitMock); + expect(response.redirected).toBeCalledWith({ + headers: { + location: '/mock-server-basepath/app/home', + }, + }); }); - it('with more than one workspace', async () => { + it('with / request path and default workspace', async () => { const request = httpServerMock.createOpenSearchDashboardsRequest({ path: '/', }); + setupMock.getStartServices.mockResolvedValue([ + { + ...coreMock.createStart(), + uiSettings: { + asScopedToClient: () => ({ + ...uiSettingsMock, + get: jest.fn().mockImplementation((key) => { + if (key === 'defaultWorkspace') { + return Promise.resolve('defaultWorkspace'); + } else if (key === 'home:useNewHomePage') { + return Promise.resolve('true'); + } + }), + }), + }, + }, + {}, + {}, + ]); const workspaceSetup = await workspacePlugin.setup(setupMock); const client = workspaceSetup.client; jest.spyOn(client, 'list').mockResolvedValue({ success: true, - result: { total: 1 }, + result: { + total: 2, + per_page: 100, + page: 1, + workspaces: [ + { id: 'defaultWorkspace', name: 'default-workspace' }, + { id: 'workspace-2', name: 'workspace-2' }, + ], + }, }); const toolKitMock = httpServerMock.createToolkit(); + await registerOnPostAuthFn(request, response, toolKitMock); + expect(response.redirected).toBeCalledWith({ + headers: { + location: '/mock-server-basepath/w/defaultWorkspace/app/workspace_navigation', + }, + }); + }); + + it('with / request path and home:useNewHomePage is false', async () => { + const request = httpServerMock.createOpenSearchDashboardsRequest({ + path: '/', + }); + setupMock.getStartServices.mockResolvedValue([ + { + ...coreMock.createStart(), + uiSettings: { + asScopedToClient: () => ({ + ...uiSettingsMock, + get: jest.fn().mockResolvedValue(false), + }), + }, + }, + {}, + {}, + ]); + const toolKitMock = httpServerMock.createToolkit(); + await registerOnPostAuthFn(request, response, toolKitMock); expect(toolKitMock.next).toBeCalledTimes(1); }); diff --git a/src/plugins/workspace/server/plugin.ts b/src/plugins/workspace/server/plugin.ts index 6d9c46ed9dc8..d7c1ba69206c 100644 --- a/src/plugins/workspace/server/plugin.ts +++ b/src/plugins/workspace/server/plugin.ts @@ -23,6 +23,7 @@ import { WORKSPACE_UI_SETTINGS_CLIENT_WRAPPER_ID, PRIORITY_FOR_WORKSPACE_UI_SETTINGS_WRAPPER, WORKSPACE_INITIAL_APP_ID, + WORKSPACE_NAVIGATION_APP_ID, } from '../common/constants'; import { IWorkspaceClientImpl, WorkspacePluginSetup, WorkspacePluginStart } from './types'; import { WorkspaceClient } from './workspace_client'; @@ -113,14 +114,51 @@ export class WorkspacePlugin implements Plugin { const path = request.url.pathname; if (path === '/') { + const [coreStart] = await core.getStartServices(); + const uiSettings = coreStart.uiSettings.asScopedToClient( + coreStart.savedObjects.getScopedClient(request) + ); + const useNewHomePage = await uiSettings.get('home:useNewHomePage'); + if (!useNewHomePage) { + return toolkit.next(); + } + const workspaceListResponse = await this.client?.list( { request, logger: this.logger }, - { page: 1, perPage: 1 } + { page: 1, perPage: 100 } ); + const basePath = core.http.basePath.serverBasePath; + if (workspaceListResponse?.success && workspaceListResponse.result.total > 0) { - return toolkit.next(); + const workspaceList = workspaceListResponse.result.workspaces; + // If user only has one workspace, go to overview page of that workspace + if (workspaceList.length === 1) { + return response.redirected({ + headers: { + location: `${basePath}/w/${workspaceList[0].id}/app/${WORKSPACE_NAVIGATION_APP_ID}`, + }, + }); + } + // Temporarily use defaultWorkspace as a placeholder + const defaultWorkspaceId = await uiSettings.get('defaultWorkspace'); + const defaultWorkspace = workspaceList.find( + (workspace) => workspace.id === defaultWorkspaceId + ); + // If user has a default workspace configured, go to overview page of that workspace + // If user has more than one workspaces, go to homepage + if (defaultWorkspace) { + return response.redirected({ + headers: { + location: `${basePath}/w/${defaultWorkspace.id}/app/${WORKSPACE_NAVIGATION_APP_ID}`, + }, + }); + } else { + return response.redirected({ + headers: { location: `${basePath}/app/home` }, + }); + } } - const basePath = core.http.basePath.serverBasePath; + // If user has no workspaces, go to initial page return response.redirected({ headers: { location: `${basePath}/app/${WORKSPACE_INITIAL_APP_ID}` }, }); From e1791ad3353c686e9f5b35ec573a30a9ef218b0c Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:04:40 +0800 Subject: [PATCH 237/276] Fix query assistant fetching agent bug (#7804) (#7819) * Fix query assistant fetching agent bug * Add changelog * fix style * Add UT --------- (cherry picked from commit 3364d0c1cafddea3ab48dd3143045a6d258c64c6) Signed-off-by: Liyun Xiu Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- changelogs/fragments/7804.yml | 2 ++ .../server/routes/query_assist/agents.test.ts | 23 +++++++++++++++++++ .../server/routes/query_assist/agents.ts | 8 ++++--- 3 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 changelogs/fragments/7804.yml diff --git a/changelogs/fragments/7804.yml b/changelogs/fragments/7804.yml new file mode 100644 index 000000000000..cda968bd641b --- /dev/null +++ b/changelogs/fragments/7804.yml @@ -0,0 +1,2 @@ +fix: +- Fix query assistant fetching agent bug ([#7804](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7804)) \ No newline at end of file diff --git a/src/plugins/query_enhancements/server/routes/query_assist/agents.test.ts b/src/plugins/query_enhancements/server/routes/query_assist/agents.test.ts index 5e31191c9c97..a9ddbf16ea23 100644 --- a/src/plugins/query_enhancements/server/routes/query_assist/agents.test.ts +++ b/src/plugins/query_enhancements/server/routes/query_assist/agents.test.ts @@ -110,4 +110,27 @@ describe('Agents helper functions', () => { ); expect(response.body.inference_results[0].output[0].result).toEqual('test response'); }); + + it('searches for agent id and response contains ml_configuration', async () => { + mockedTransport + .mockResolvedValueOnce({ + body: { + type: 'agent', + ml_configuration: { agent_id: 'new-id' }, + }, + }) + .mockResolvedValueOnce({ + body: { inference_results: [{ output: [{ result: 'test response' }] }] }, + }); + const response = await requestAgentByConfig({ + context, + configName: 'new_agent', + body: { parameters: { param1: 'value1' } }, + }); + expect(mockedTransport).toBeCalledWith( + expect.objectContaining({ path: '/_plugins/_ml/agents/new-id/_execute' }), + expect.anything() + ); + expect(response.body.inference_results[0].output[0].result).toEqual('test response'); + }); }); diff --git a/src/plugins/query_enhancements/server/routes/query_assist/agents.ts b/src/plugins/query_enhancements/server/routes/query_assist/agents.ts index d065254c7f05..f3c2b8676b67 100644 --- a/src/plugins/query_enhancements/server/routes/query_assist/agents.ts +++ b/src/plugins/query_enhancements/server/routes/query_assist/agents.ts @@ -37,11 +37,13 @@ export const getAgentIdByConfig = async ( method: 'GET', path: `${URI.ML}/config/${configName}`, })) as ApiResponse<{ type: string; configuration: { agent_id?: string } }>; - - if (!response || response.body.configuration.agent_id === undefined) { + if ( + !response || + !(response.body.ml_configuration?.agent_id || response.body.configuration?.agent_id) + ) { throw new Error('cannot find any agent by configuration: ' + configName); } - return response.body.configuration.agent_id; + return response.body.ml_configuration?.agent_id || response.body.configuration.agent_id; } catch (error) { const errorMessage = JSON.stringify(error.meta?.body) || error; throw new Error(`Get agent '${configName}' failed, reason: ` + errorMessage); From ccec03d22427e3d9165603d8310b6737a4227083 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:10:21 +0800 Subject: [PATCH 238/276] Fix the adoption of the new header in the index pattern management pages (#7827) (#7828) (cherry picked from commit c3fb7e40061589330a02c4fa987d9586fdb71b80) Signed-off-by: Miki Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../create_index_pattern_wizard.tsx | 64 ++++++++----- .../edit_index_pattern/edit_index_pattern.tsx | 42 +++++---- .../index_header/index_header.tsx | 89 +++++++------------ .../index_pattern_table.tsx | 4 +- 4 files changed, 101 insertions(+), 98 deletions(-) diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx index 6f02c98aa4f8..f930bf526fa1 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx @@ -35,6 +35,7 @@ import { EuiGlobalToastListToast, EuiPageContent, EuiHorizontalRule, + EuiCode, } from '@elastic/eui'; import { FormattedMessage } from '@osd/i18n/react'; import { i18n } from '@osd/i18n'; @@ -65,6 +66,7 @@ import { DataSourceRef, IndexPatternManagmentContextValue } from '../../types'; import { MatchedItem } from './types'; import { DuplicateIndexPatternError, IndexPattern } from '../../../../data/public'; import { StepDataSource } from './components/step_data_source'; +import { TopNavControlDescriptionData } from '../../../../navigation/public'; interface CreateIndexPatternWizardState { step: StepType; @@ -298,6 +300,38 @@ export class CreateIndexPatternWizard extends Component< const header = this.renderHeader(); + const descriptionHeaderControl = useUpdatedUX ? ( + multiple, + single: filebeat-4-3-22, + star: filebeat-*, + }} + /> + ) as unknown) as string, + links: [ + { + href: docLinks.links.noDocumentation.indexPatterns.introduction, + controlType: 'link', + flush: 'both', + target: '_blank', + label: i18n.translate('indexPatternManagement.createIndexPattern.documentation', { + defaultMessage: 'Read documentation', + }), + }, + ], + } as TopNavControlDescriptionData, + ]} + setMountPoint={application.setAppDescriptionControls} + /> + ) : null; + if (step === DATA_SOURCE_STEP) { const component = ( ); + return useUpdatedUX ? ( <> {component} - , - }, - ]} - setMountPoint={application.setAppDescriptionControls} - /> + {descriptionHeaderControl} ) : ( @@ -346,18 +374,12 @@ export class CreateIndexPatternWizard extends Component< catchAndWarn={this.catchAndWarn} /> ); + return useUpdatedUX ? ( <> {/* Except StepDataSource, other components need to use PageContent to wrap when using new UX */} {component} - , - }, - ]} - setMountPoint={application.setAppDescriptionControls} - /> + {descriptionHeaderControl} ) : ( @@ -380,18 +402,12 @@ export class CreateIndexPatternWizard extends Component< stepInfo={stepInfo} /> ); + return useUpdatedUX ? ( <> {/* Except StepDataSource, other components need to use PageContent to wrap when using new UX */} {component} - , - }, - ]} - setMountPoint={application.setAppDescriptionControls} - /> + {descriptionHeaderControl} ) : ( diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx index a39dcd6cc5a2..e5f87af2e974 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx @@ -50,6 +50,7 @@ import { Tabs } from './tabs'; import { IndexHeader } from './index_header'; import { IndexPatternTableItem } from '../types'; import { getIndexPatterns } from '../utils'; +import { TopNavControlDescriptionData } from '../../../../navigation/public'; export interface EditIndexPatternProps extends RouteComponentProps { indexPattern: IndexPattern; @@ -201,32 +202,41 @@ export const EditIndexPattern = withRouter( const useUpdatedUX = uiSettings.get('home:useNewHomePage'); const renderDescription = () => { - const component = ( - -

- {indexPattern.title} }} - />{' '} - - {mappingAPILink} - -

-
+ const descriptionText = ( + {indexPattern.title} }} + /> ); return useUpdatedUX ? ( ) : ( - component + +

+ {descriptionText}{' '} + + {mappingAPILink} + +

+
); }; diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx index 156a22f720f5..f7f0edaea4d6 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx @@ -30,18 +30,11 @@ import React from 'react'; import { i18n } from '@osd/i18n'; -import { - EuiFlexGroup, - EuiToolTip, - EuiFlexItem, - EuiSmallButtonIcon, - EuiText, - EuiButtonIcon, - EuiButton, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiToolTip, EuiFlexItem, EuiSmallButtonIcon, EuiText } from '@elastic/eui'; import { IIndexPattern } from 'src/plugins/data/public'; import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; import { IndexPatternManagmentContext } from '../../../types'; +import { TopNavControlButtonData, TopNavControlIconData } from '../../../../../navigation/public'; interface IndexHeaderProps { indexPattern: IIndexPattern; @@ -102,65 +95,49 @@ export function IndexHeader({ ...(deleteIndexPatternClick ? [ { - renderComponent: ( - - - - ), - }, + color: 'danger', + run: deleteIndexPatternClick, + iconType: 'trash', + ariaLabel: removeAriaLabel, + testId: 'deleteIndexPatternButton', + display: 'base', + controlType: 'icon', + tooltip: removeTooltip, + } as TopNavControlIconData, ] : []), ...(defaultIndex !== indexPattern.id && setDefault ? [ { - renderComponent: ( - - {i18n.translate( - 'indexPatternManagement.editIndexPattern.setDefaultButton.text', - { - defaultMessage: 'Set as default index', - } - )} - + run: setDefault, + ariaLabel: setDefaultAriaLabel, + testId: 'setDefaultIndexPatternButton', + label: i18n.translate( + 'indexPatternManagement.editIndexPattern.setDefaultButton.text', + { + defaultMessage: 'Set as default index', + } ), - }, + controlType: 'button', + } as TopNavControlButtonData, ] : []), ...(refreshFields ? [ { - renderComponent: ( - - {i18n.translate( - 'indexPatternManagement.editIndexPattern.refreshFieldsButton.text', - { - defaultMessage: 'Refresh field list', - } - )} - + run: refreshFields, + iconType: 'refresh', + ariaLabel: refreshAriaLabel, + testId: 'refreshFieldsIndexPatternButton', + fill: true, + label: i18n.translate( + 'indexPatternManagement.editIndexPattern.refreshFieldsButton.text', + { + defaultMessage: 'Refresh field list', + } ), - }, + controlType: 'button', + } as TopNavControlButtonData, ] : []), ]} diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx index 3a1d6323323c..d849842e00ad 100644 --- a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx @@ -243,12 +243,12 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { ); })(); - const description = ( + const description = (( - ); + ) as unknown) as string; const pageTitleAndDescription = showActionsInHeader ? ( Date: Mon, 26 Aug 2024 13:09:20 +0800 Subject: [PATCH 239/276] [Workspace] Update workspace list page table (#7640) (#7761) * the table basically works * the table basically works new * This time I achieve the functionality and apprearence of the workLists table * This time I achieve the functionality and apprearence of the workLists table, add tests * This time I achieve the functionality and apprearence of the workLists table, add tests * Achieve the functionality and apprearence of the workLists table, and add tests * Changeset file for PR #7640 created/updated * Changeset file for PR #7640 created/updated * Changeset file for PR #7640 created/updated * Achieve the functionality and apprearence of the work List table page, add tests, and refine based the comments * Achieve the functionality and apprearence of the work List table page, add tests, and update based the comments * Achieve the functionality and apprearence of the work List table page, add tests, and update based the comment-1 * Achieve the functionality and apprearence of the work List table page, add tests, and update based the comment-1 * Enable multiple deletion and correct the code based on comments * Enable multiple deletion and correct the code based on comments * set the advanced date format * set advanced time format and tests --------- (cherry picked from commit e70bfad24b0a1b809713ea69faf1c15ec86909cb) Signed-off-by: Qxisylolo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: SuZhou-Joe --- changelogs/fragments/7640.yml | 2 + .../delete_workspace_modal.test.tsx.snap | 44 +- .../delete_workspace_modal.test.tsx | 64 +-- .../delete_workspace_modal.tsx | 114 ++-- .../__snapshots__/index.test.tsx.snap | 508 +++++++++++------- .../components/workspace_list/index.test.tsx | 175 ++++-- .../components/workspace_list/index.tsx | 308 ++++++++--- 7 files changed, 805 insertions(+), 410 deletions(-) create mode 100644 changelogs/fragments/7640.yml diff --git a/changelogs/fragments/7640.yml b/changelogs/fragments/7640.yml new file mode 100644 index 000000000000..5a93e3bdb5d9 --- /dev/null +++ b/changelogs/fragments/7640.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace] Update workspace list page table ([#7640](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7640)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/delete_workspace_modal/__snapshots__/delete_workspace_modal.test.tsx.snap b/src/plugins/workspace/public/components/delete_workspace_modal/__snapshots__/delete_workspace_modal.test.tsx.snap index c34ad92fcc2e..604d6a5edb66 100644 --- a/src/plugins/workspace/public/components/delete_workspace_modal/__snapshots__/delete_workspace_modal.test.tsx.snap +++ b/src/plugins/workspace/public/components/delete_workspace_modal/__snapshots__/delete_workspace_modal.test.tsx.snap @@ -47,49 +47,7 @@ exports[`DeleteWorkspaceModal should render normally 1`] = ` >
-
-

- The following workspace will be permanently deleted. This action cannot be undone. -

-
    -
    -
    -
    - To confirm your action, type - - delete - - . -
    -
    -
    -
    - -
    -
    -
    -
+ />
{ const onDeleteSuccessFn = jest.fn(); const newProps = { ...defaultProps, - selectedWorkspace: { - id: 'test', - name: 'test', - }, + selectedWorkspaces: [ + { + id: 'test', + name: 'test', + }, + ], onClose: onCloseFn, onDeleteSuccess: onDeleteSuccessFn, }; @@ -99,10 +101,10 @@ describe('DeleteWorkspaceModal', () => { }); }); - it('should not call deleteWorkspace if passed selectedWorkspace is null', async () => { + it('should not call deleteWorkspace modal if passed selectedWorkspace is null', async () => { const newProps = { ...defaultProps, - selectedWorkspace: null, + selectedWorkspace: [], }; const deleteFn = jest.fn().mockReturnValue({ success: true, @@ -114,26 +116,20 @@ describe('DeleteWorkspaceModal', () => { delete: deleteFn, }, }; - const { getByTestId, findByTestId } = render( - getWrapWorkspaceDeleteModalInContext(newProps, newServices) - ); - await findByTestId('delete-workspace-modal-input'); - const input = getByTestId('delete-workspace-modal-input'); - fireEvent.change(input, { - target: { value: 'delete' }, - }); - const confirmButton = getByTestId('delete-workspace-modal-confirm'); - fireEvent.click(confirmButton); - expect(deleteFn).not.toHaveBeenCalled(); + const { queryByTestId } = render(getWrapWorkspaceDeleteModalInContext(newProps, newServices)); + const input = queryByTestId('delete-workspace-modal-input'); + expect(input).not.toBeInTheDocument(); }); - it('should add danger is returned data is unsuccess', async () => { + it('should add danger if returned data is unsuccess', async () => { const newProps = { ...defaultProps, - selectedWorkspace: { - id: 'test', - name: 'test', - }, + selectedWorkspaces: [ + { + id: 'test', + name: 'test', + }, + ], }; const deleteFn = jest.fn().mockReturnValue({ success: false, @@ -165,10 +161,12 @@ describe('DeleteWorkspaceModal', () => { it('confirm button should be disabled if not input delete', async () => { const newProps = { ...defaultProps, - selectedWorkspace: { - id: 'test', - name: 'test', - }, + selectedWorkspaces: [ + { + id: 'test', + name: 'test', + }, + ], }; const deleteFn = jest.fn().mockReturnValue({ success: false, @@ -186,7 +184,7 @@ describe('DeleteWorkspaceModal', () => { await findByTestId('delete-workspace-modal-input'); const input = getByTestId('delete-workspace-modal-input'); fireEvent.change(input, { - target: { value: 'delet' }, + target: { value: 'delete' }, }); const confirmButton = getByTestId('delete-workspace-modal-confirm'); expect(confirmButton.hasAttribute('disabled')); @@ -196,10 +194,12 @@ describe('DeleteWorkspaceModal', () => { const onCloseFn = jest.fn(); const newProps = { ...defaultProps, - selectedWorkspace: { - id: 'test', - name: 'test', - }, + selectedWorkspaces: [ + { + id: 'test', + name: 'test', + }, + ], onclose: onCloseFn, }; const deleteFn = jest.fn().mockImplementation(() => { diff --git a/src/plugins/workspace/public/components/delete_workspace_modal/delete_workspace_modal.tsx b/src/plugins/workspace/public/components/delete_workspace_modal/delete_workspace_modal.tsx index e6a3558a50d2..01a98d82bdd3 100644 --- a/src/plugins/workspace/public/components/delete_workspace_modal/delete_workspace_modal.tsx +++ b/src/plugins/workspace/public/components/delete_workspace_modal/delete_workspace_modal.tsx @@ -23,49 +23,53 @@ import { WorkspaceClient } from '../../workspace_client'; export interface DeleteWorkspaceModalProps { onClose: () => void; - selectedWorkspace?: WorkspaceAttribute | null; + selectedWorkspaces?: WorkspaceAttribute[]; onDeleteSuccess?: () => void; } export function DeleteWorkspaceModal(props: DeleteWorkspaceModalProps) { const [value, setValue] = useState(''); - const { onClose, selectedWorkspace, onDeleteSuccess } = props; + const { onClose, selectedWorkspaces, onDeleteSuccess } = props; const { services: { notifications, workspaceClient }, } = useOpenSearchDashboards<{ workspaceClient: WorkspaceClient }>(); - const deleteWorkspace = async () => { - if (selectedWorkspace?.id) { - let result; - try { - result = await workspaceClient.delete(selectedWorkspace?.id); - } catch (error) { - notifications?.toasts.addDanger({ - title: i18n.translate('workspace.delete.failed', { - defaultMessage: 'Failed to delete workspace', - }), - text: error instanceof Error ? error.message : JSON.stringify(error), - }); - return onClose(); - } - if (result?.success) { - notifications?.toasts.addSuccess({ - title: i18n.translate('workspace.delete.success', { - defaultMessage: 'Delete workspace successfully', - }), - }); - onClose(); - if (onDeleteSuccess) { - onDeleteSuccess(); + const deleteWorkspaces = async () => { + if (selectedWorkspaces && selectedWorkspaces.length > 0) { + selectedWorkspaces.forEach(async (selectedWorkspace) => { + if (selectedWorkspace?.id) { + let result; + try { + result = await workspaceClient.delete(selectedWorkspace?.id); + } catch (error) { + notifications?.toasts.addDanger({ + title: i18n.translate('workspace.delete.failed', { + defaultMessage: 'Failed to delete workspace', + }), + text: error instanceof Error ? error.message : JSON.stringify(error), + }); + return onClose(); + } + if (result?.success) { + notifications?.toasts.addSuccess({ + title: i18n.translate('workspace.delete.success', { + defaultMessage: 'Delete workspace successfully', + }), + }); + onClose(); + if (onDeleteSuccess) { + onDeleteSuccess(); + } + } else { + notifications?.toasts.addDanger({ + title: i18n.translate('workspace.delete.failed', { + defaultMessage: 'Failed to delete workspace', + }), + text: result?.error, + }); + } } - } else { - notifications?.toasts.addDanger({ - title: i18n.translate('workspace.delete.failed', { - defaultMessage: 'Failed to delete workspace', - }), - text: result?.error, - }); - } + }); } }; @@ -76,23 +80,31 @@ export function DeleteWorkspaceModal(props: DeleteWorkspaceModalProps) { -
-

The following workspace will be permanently deleted. This action cannot be undone.

-
    - {selectedWorkspace?.name ?
  • {selectedWorkspace.name}
  • : null} -
- - - To confirm your action, type delete. - - setValue(e.target.value)} - /> -
+ {selectedWorkspaces && selectedWorkspaces.length > 0 ? ( +
+

+ The following workspace will be permanently deleted. This action cannot be undone. +

+
    + {selectedWorkspaces.map((selectedWorkspace) => { + return selectedWorkspace?.name ? ( +
  • {selectedWorkspace.name}
  • + ) : null; + })} +
+ + + To confirm your action, type delete. + + setValue(e.target.value)} + /> +
+ ) : null}
@@ -104,7 +116,7 @@ export function DeleteWorkspaceModal(props: DeleteWorkspaceModalProps) {
+
+
+
+
+ +
+
+
+
+ > +
+ +
+ +
+
@@ -130,6 +192,29 @@ exports[`WorkspaceList should render title and table normally 1`] = ` />
+ @@ -240,8 +321,32 @@ exports[`WorkspaceList should render title and table normally 1`] = ` + + + diff --git a/src/plugins/workspace/public/components/workspace_list/index.test.tsx b/src/plugins/workspace/public/components/workspace_list/index.test.tsx index 2284008d9d36..f45f5feaf860 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.test.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.test.tsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import moment from 'moment'; import { BehaviorSubject, of } from 'rxjs'; import { render, fireEvent, screen } from '@testing-library/react'; import { I18nProvider } from '@osd/i18n/react'; @@ -15,6 +16,18 @@ import { WorkspaceList } from './index'; jest.mock('../utils/workspace'); +const mockNavigatorWrite = jest.fn(); + +jest.mock('@elastic/eui', () => { + const original = jest.requireActual('@elastic/eui'); + return { + ...original, + copyToClipboard: jest.fn().mockImplementation((id) => { + mockNavigatorWrite(id); + }), + }; +}); + jest.mock('../delete_workspace_modal', () => ({ DeleteWorkspaceModal: ({ onClose }: { onClose: () => void }) => (
@@ -25,9 +38,29 @@ jest.mock('../delete_workspace_modal', () => ({ function getWrapWorkspaceListInContext( workspaceList = [ - { id: 'id1', name: 'name1', features: ['use-case-all'] }, - { id: 'id2', name: 'name2' }, - { id: 'id3', name: 'name3', features: ['use-case-observability'] }, + { + id: 'id1', + name: 'name1', + features: ['use-case-all'], + description: + 'should be able to see the description tooltip when hovering over the description', + lastUpdatedTime: '1999-08-06T02:00:00.00Z', + }, + { + id: 'id2', + name: 'name2', + features: ['use-case-observability'], + description: + 'should be able to see the description tooltip when hovering over the description', + lastUpdatedTime: '1999-08-06T00:00:00.00Z', + }, + { + id: 'id3', + name: 'name3', + features: ['use-case-search'], + description: '', + lastUpdatedTime: '1999-08-06T01:00:00.00Z', + }, ], isDashboardAdmin = true ) { @@ -48,6 +81,14 @@ function getWrapWorkspaceListInContext( workspaces: { workspaceList$: of(workspaceList), }, + uiSettings: { + get: jest.fn().mockImplementation((key) => { + if (key === 'dateFormat') { + return 'MMM D, YYYY @ HH:mm:ss.SSS'; + } + return null; + }), + }, navigationUI: { HeaderControl: mockHeaderControl, }, @@ -84,26 +125,27 @@ describe('WorkspaceList', () => { expect(getByText('Analytics (All)')).toBeInTheDocument(); expect(getByText('Observability')).toBeInTheDocument(); }); - it('should be able to apply debounce search after input', async () => { - const list = [ - { id: 'id1', name: 'name1' }, - { id: 'id2', name: 'name2' }, - { id: 'id3', name: 'name3' }, - { id: 'id4', name: 'name4' }, - { id: 'id5', name: 'name5' }, - { id: 'id6', name: 'name6' }, - ]; - const { getByText, getByRole, queryByText } = render(getWrapWorkspaceListInContext(list)); - expect(getByText('name1')).toBeInTheDocument(); - expect(queryByText('name6')).not.toBeInTheDocument(); + + it('should be able to search and re-render the list', async () => { + const { getByText, getByRole, queryByText } = render(getWrapWorkspaceListInContext()); const input = getByRole('searchbox'); fireEvent.change(input, { - target: { value: 'nam' }, + target: { value: 'name2' }, }); + expect(getByText('name2')).toBeInTheDocument(); + expect(queryByText('name1')).not.toBeInTheDocument(); + expect(queryByText('name3')).not.toBeInTheDocument(); + }); + + it('should be able to apply debounce search after input', async () => { + const { getByText, getByRole, queryByText } = render(getWrapWorkspaceListInContext()); + const input = getByRole('searchbox'); fireEvent.change(input, { - target: { value: 'name6' }, + target: { value: 'name2' }, }); - expect(queryByText('name6')).not.toBeInTheDocument(); + expect(getByText('name2')).toBeInTheDocument(); + expect(queryByText('name1')).not.toBeInTheDocument(); + expect(queryByText('name3')).not.toBeInTheDocument(); }); it('should be able to switch workspace after clicking name', async () => { @@ -113,16 +155,51 @@ describe('WorkspaceList', () => { expect(navigateToWorkspaceDetail).toBeCalled(); }); + it('should be able to perform the time format transformation', async () => { + const { getByText } = render(getWrapWorkspaceListInContext()); + expect( + getByText(moment('1999-08-06T00:00:00.00Z').format('MMM D, YYYY @ HH:mm:ss.SSS')) + ).toBeInTheDocument(); + expect( + getByText(moment('1999-08-06T01:00:00.00Z').format('MMM D, YYYY @ HH:mm:ss.SSS')) + ).toBeInTheDocument(); + expect( + getByText(moment('1999-08-06T02:00:00.00Z').format('MMM D, YYYY @ HH:mm:ss.SSS')) + ).toBeInTheDocument(); + }); + + it('should be able to see the 3 operations: copy, update, delete after click in the meatballs button', async () => { + const { getAllByTestId, getByText } = render(getWrapWorkspaceListInContext()); + const operationIcons = getAllByTestId('euiCollapsedItemActionsButton')[0]; + fireEvent.click(operationIcons); + expect(getByText('Copy ID')).toBeInTheDocument(); + expect(getByText('Edit')).toBeInTheDocument(); + expect(getByText('Delete')).toBeInTheDocument(); + }); + + it('should be able to copy workspace ID after clicking copy button', async () => { + const { getByText, getAllByTestId } = render(getWrapWorkspaceListInContext()); + const operationIcons = getAllByTestId('euiCollapsedItemActionsButton')[0]; + fireEvent.click(operationIcons); + const copyIcon = getByText('Copy ID'); + fireEvent.click(copyIcon); + expect(mockNavigatorWrite).toHaveBeenCalledWith('id1'); + }); + it('should be able to update workspace after clicking name', async () => { - const { getAllByTestId } = render(getWrapWorkspaceListInContext()); - const editIcon = getAllByTestId('workspace-list-edit-icon')[0]; + const { getByText, getAllByTestId } = render(getWrapWorkspaceListInContext()); + const operationIcons = getAllByTestId('euiCollapsedItemActionsButton')[0]; + fireEvent.click(operationIcons); + const editIcon = getByText('Edit'); fireEvent.click(editIcon); expect(navigateToWorkspaceDetail).toBeCalled(); }); it('should be able to call delete modal after clicking delete button', async () => { - const { getAllByTestId } = render(getWrapWorkspaceListInContext()); - const deleteIcon = getAllByTestId('workspace-list-delete-icon')[0]; + const { getByText, getAllByTestId } = render(getWrapWorkspaceListInContext()); + const operationIcons = getAllByTestId('euiCollapsedItemActionsButton')[0]; + fireEvent.click(operationIcons); + const deleteIcon = getByText('Delete'); fireEvent.click(deleteIcon); expect(screen.queryByLabelText('mock delete workspace modal')).toBeInTheDocument(); const modalCancelButton = screen.getByLabelText('mock delete workspace modal button'); @@ -132,12 +209,48 @@ describe('WorkspaceList', () => { it('should be able to pagination when clicking pagination button', async () => { const list = [ - { id: 'id1', name: 'name1' }, - { id: 'id2', name: 'name2' }, - { id: 'id3', name: 'name3' }, - { id: 'id4', name: 'name4' }, - { id: 'id5', name: 'name5' }, - { id: 'id6', name: 'name6' }, + { + id: 'id1', + name: 'name1', + features: ['use-case-all'], + description: '', + lastUpdatedTime: '2024-08-06T00:00:00.00Z', + }, + { + id: 'id2', + name: 'name2', + features: ['use-case-observability'], + description: '', + lastUpdatedTime: '2024-08-06T00:00:00.00Z', + }, + { + id: 'id3', + name: 'name3', + features: ['use-case-search'], + description: '', + lastUpdatedTime: '2024-08-06T00:00:00.00Z', + }, + { + id: 'id4', + name: 'name4', + features: ['use-case-all'], + description: '', + lastUpdatedTime: '2024-08-05T00:00:00.00Z', + }, + { + id: 'id5', + name: 'name5', + features: ['use-case-observability'], + description: '', + lastUpdatedTime: '2024-08-06T00:00:00.00Z', + }, + { + id: 'id6', + name: 'name6', + features: ['use-case-search'], + description: '', + lastUpdatedTime: '2024-08-06T00:00:00.00Z', + }, ]; const { getByTestId, getByText, queryByText } = render(getWrapWorkspaceListInContext(list)); expect(getByText('name1')).toBeInTheDocument(); @@ -149,14 +262,12 @@ describe('WorkspaceList', () => { }); it('should display create workspace button for dashboard admin', async () => { - const { getByText } = render(getWrapWorkspaceListInContext([], true)); - - expect(getByText('Create workspace')).toBeInTheDocument(); + const { getAllByText } = render(getWrapWorkspaceListInContext([], true)); + expect(getAllByText('Create workspace')[0]).toBeInTheDocument(); }); it('should hide create workspace button for non dashboard admin', async () => { const { queryByText } = render(getWrapWorkspaceListInContext([], false)); - expect(queryByText('Create workspace')).toBeNull(); }); }); diff --git a/src/plugins/workspace/public/components/workspace_list/index.tsx b/src/plugins/workspace/public/components/workspace_list/index.tsx index 931862b919a7..91fa716890bc 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.tsx @@ -4,19 +4,26 @@ */ import React, { useState, useMemo, useCallback } from 'react'; +import moment from 'moment'; import { EuiPage, EuiPageContent, EuiLink, EuiSmallButton, EuiInMemoryTable, + EuiToolTip, + EuiText, EuiSearchBarProps, + copyToClipboard, + EuiTableSelectionType, + EuiButtonEmpty, + EuiButton, + EuiEmptyPrompt, } from '@elastic/eui'; import useObservable from 'react-use/lib/useObservable'; import { BehaviorSubject, of } from 'rxjs'; import { i18n } from '@osd/i18n'; -import { debounce, DEFAULT_NAV_GROUPS } from '../../../../../core/public'; -import { WorkspaceAttribute } from '../../../../../core/public'; +import { DEFAULT_NAV_GROUPS, WorkspaceAttribute } from '../../../../../core/public'; import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public'; import { navigateToWorkspaceDetail } from '../utils/workspace'; @@ -31,6 +38,10 @@ export interface WorkspaceListProps { registeredUseCases$: BehaviorSubject; } +interface WorkspaceAttributeWithUseCaseID extends WorkspaceAttribute { + useCase?: string; +} + export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { const { services: { @@ -38,47 +49,52 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { application, http, navigationUI: { HeaderControl }, + uiSettings, }, } = useOpenSearchDashboards<{ navigationUI: NavigationPublicPluginStart['ui']; }>(); const registeredUseCases = useObservable(registeredUseCases$); const isDashboardAdmin = application?.capabilities?.dashboards?.isDashboardAdmin; - const initialSortField = 'name'; const initialSortDirection = 'asc'; const workspaceList = useObservable(workspaces?.workspaceList$ ?? of([]), []); - const [queryInput, setQueryInput] = useState(''); + const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 5, pageSizeOptions: [5, 10, 20], }); - const [deletedWorkspace, setDeletedWorkspace] = useState(null); + const [deletedWorkspaces, setDeletedWorkspaces] = useState([]); + const [selection, setSelection] = useState([]); - const handleSwitchWorkspace = useCallback( - (id: string) => { - if (application && http) { - navigateToWorkspaceDetail({ application, http }, id); + const dateFormat = uiSettings?.get('dateFormat'); + + const extractUseCaseFromFeatures = useCallback( + (features: string[]) => { + if (!features || features.length === 0) { + return ''; + } + const useCaseId = getFirstUseCaseOfFeatureConfigs(features); + const usecase = + useCaseId === DEFAULT_NAV_GROUPS.all.id + ? DEFAULT_NAV_GROUPS.all + : registeredUseCases?.find(({ id }) => id === useCaseId); + if (usecase) { + return usecase.title; } }, - [application, http] + [registeredUseCases] ); - const searchResult = useMemo(() => { - if (queryInput) { - const normalizedQuery = queryInput.toLowerCase(); - const result = workspaceList.filter((item) => { - return ( - item.id.toLowerCase().indexOf(normalizedQuery) > -1 || - item.name.toLowerCase().indexOf(normalizedQuery) > -1 - ); - }); - return result; - } - return workspaceList; - }, [workspaceList, queryInput]); - + const newWorkspaceList: WorkspaceAttributeWithUseCaseID[] = useMemo(() => { + return workspaceList.map( + (workspace): WorkspaceAttributeWithUseCaseID => ({ + ...workspace, + useCase: extractUseCaseFromFeatures(workspace.features ?? []), + }) + ); + }, [workspaceList, extractUseCaseFromFeatures]); const workspaceCreateUrl = useMemo(() => { if (!application) { return ''; @@ -92,6 +108,38 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { return appUrl; }, [application]); + const emptyStateMessage = useMemo(() => { + return ( + + {i18n.translate('workspace.workspaceList.emptyState.title', { + defaultMessage: 'No workspace available', + })} + + } + titleSize="s" + body={i18n.translate('workspace.workspaceList.emptyState.body', { + defaultMessage: 'There are no workspace to display. Create workspace to get started.', + })} + actions={ + isDashboardAdmin && ( + + {i18n.translate('workspace.workspaceList.buttons.createWorkspace', { + defaultMessage: 'Create workspace', + })} + + ) + } + /> + ); + }, [isDashboardAdmin, workspaceCreateUrl]); + const renderCreateWorkspaceButton = () => { const button = ( { ); }; + const handleCopyId = (id: string) => { + copyToClipboard(id); + }; + + const handleSwitchWorkspace = useCallback( + (id: string) => { + if (application && http) { + navigateToWorkspaceDetail({ application, http }, id); + } + }, + [application, http] + ); + + const renderToolsLeft = () => { + if (selection.length === 0) { + return; + } + + const onClick = () => { + const deleteWorkspacesByIds = (workSpaces: WorkspaceAttribute[], ids: string[]) => { + const needToBeDeletedWorkspaceList: WorkspaceAttribute[] = []; + ids.forEach((id) => { + const index = workSpaces.findIndex((workSpace) => workSpace.id === id); + if (index >= 0) { + needToBeDeletedWorkspaceList.push(workSpaces[index]); + } + }); + return needToBeDeletedWorkspaceList; + }; + + setDeletedWorkspaces( + deleteWorkspacesByIds( + newWorkspaceList, + selection.map((item) => item.id) + ) + ); + + setSelection([]); + }; + + return ( + <> + + Delete {selection.length} Workspace + + {deletedWorkspaces && deletedWorkspaces.length > 0 && ( + setDeletedWorkspaces([])} + /> + )} + + ); + }; + + const selectionValue: EuiTableSelectionType = { + onSelectionChange: (deletedSelection) => setSelection(deletedSelection), + }; + + const search: EuiSearchBarProps = { + box: { + incremental: true, + }, + filters: [ + { + type: 'field_value_selection', + field: 'useCase', + name: 'Use Case', + multiSelect: false, + options: Array.from( + new Set(newWorkspaceList.map(({ useCase }) => useCase).filter(Boolean)) + ).map((useCase) => ({ + value: useCase!, + name: useCase!, + })), + }, + ], + toolsLeft: renderToolsLeft(), + }; + const columns = [ { field: 'name', name: 'Name', + width: '25%', sortable: true, render: (name: string, item: WorkspaceAttribute) => ( - handleSwitchWorkspace(item.id)}>{name} + handleSwitchWorkspace(item.id)}> + {name} + ), }, + { - field: 'id', - name: 'ID', - sortable: true, + field: 'useCase', + name: 'Use case', + width: '20%', }, + { field: 'description', name: 'Description', - truncateText: true, + width: '20%', + render: (description: string) => ( + + {/* Here I need to set width mannuly as the tooltip will ineffect the property : truncateText ', */} + + {description} + + + ), }, { - field: 'features', - name: 'Use case', - isExpander: true, - hasActions: true, - render: (features: string[]) => { - if (!features || features.length === 0) { - return ''; - } - const useCaseId = getFirstUseCaseOfFeatureConfigs(features); - const useCase = - useCaseId === DEFAULT_NAV_GROUPS.all.id - ? DEFAULT_NAV_GROUPS.all - : registeredUseCases?.find(({ id }) => id === useCaseId); - if (useCase) { - return useCase.title; - } + field: 'lastUpdatedTime', + name: 'Last updated', + width: '25%', + truncateText: false, + render: (lastUpdatedTime: string) => { + return moment(lastUpdatedTime).format(dateFormat); }, }, + { name: 'Actions', field: '', actions: [ + { + name: 'Copy ID', + type: 'button', + description: 'Copy id', + 'data-test-subj': 'workspace-list-copy-id-icon', + render: ({ id }: WorkspaceAttribute) => { + return ( + handleCopyId(id)} + size="xs" + iconType="copy" + color="text" + > + Copy ID + + ); + }, + }, { name: 'Edit', - icon: 'pencil', type: 'icon', + icon: 'edit', + color: 'danger', description: 'Edit workspace', - onClick: ({ id }: WorkspaceAttribute) => handleSwitchWorkspace(id), 'data-test-subj': 'workspace-list-edit-icon', + onClick: ({ id }: WorkspaceAttribute) => handleSwitchWorkspace(id), + render: ({ id }: WorkspaceAttribute) => { + return ( + handleSwitchWorkspace(id)} + iconType="pencil" + size="xs" + color="text" + > + Edit + + ); + }, }, { name: 'Delete', - icon: 'trash', - type: 'icon', + type: 'button', description: 'Delete workspace', - onClick: (item: WorkspaceAttribute) => setDeletedWorkspace(item), 'data-test-subj': 'workspace-list-delete-icon', + render: (item: WorkspaceAttribute) => { + return ( + { + setDeletedWorkspaces([item]); + }} + size="xs" + iconType="trash" + color="danger" + > + Delete + + ); + }, }, ], }, ]; - const debouncedSetQueryInput = useMemo(() => { - return debounce(setQueryInput, 300); - }, [setQueryInput]); - - const handleSearchInput: EuiSearchBarProps['onChange'] = useCallback( - ({ query }) => { - debouncedSetQueryInput(query?.text ?? ''); - }, - [debouncedSetQueryInput] - ); - - const search: EuiSearchBarProps = { - onChange: handleSearchInput, - box: { - incremental: true, - }, - }; - return ( { hasShadow={false} > setPagination((prev) => { return { ...prev, pageIndex: index, pageSize: size }; @@ -233,12 +395,14 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { }} isSelectable={true} search={search} + selection={selectionValue} /> - {deletedWorkspace && ( + + {deletedWorkspaces.length > 0 && ( setDeletedWorkspace(null)} + selectedWorkspaces={deletedWorkspaces} + onClose={() => setDeletedWorkspaces([])} /> )} From 30a847b5baf3d21eeed3e8c42f979341261e2bec Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 16:08:21 +0800 Subject: [PATCH 240/276] [Workspaces]Add features in use case card and preselect first use case (#7703) (#7838) * Display features in workspace use case card * Changeset file for PR #7703 created/updated * Changeset file for PR #7703 created/updated * Changeset file for PR #7703 created/updated * Add more test cases * Update snapshort of workspace list * Address pr comments --------- (cherry picked from commit 446aa08b9730ecd4bfcbbb13e796be932ad29e7a) Signed-off-by: Lin Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7703.yml | 2 + .../use_case_footer.test.tsx | 17 +-- .../home_get_start_card/use_case_footer.tsx | 2 +- .../workspace_creator.test.tsx | 78 +++++++--- .../workspace_creator/workspace_creator.tsx | 30 +++- .../workspace_detail.test.tsx | 10 +- .../public/components/workspace_form/types.ts | 5 + .../use_form_available_use_cases.test.ts | 140 ++++++++++++++++++ .../use_form_available_use_cases.ts | 71 +++++++++ .../workspace_enter_details_panel.tsx | 9 +- .../workspace_form/workspace_form.test.tsx | 29 +++- .../workspace_form/workspace_form.tsx | 27 +++- .../workspace_use_case.test.tsx | 108 +++++++++++--- .../workspace_form/workspace_use_case.tsx | 120 +++++++++------ .../__snapshots__/index.test.tsx.snap | 4 +- .../components/workspace_list/index.test.tsx | 8 +- .../workspace_menu/workspace_menu.test.tsx | 8 +- src/plugins/workspace/public/mocks.ts | 21 +++ src/plugins/workspace/public/plugin.test.ts | 2 +- src/plugins/workspace/public/plugin.ts | 3 +- .../public/services/use_case_service.test.ts | 67 +++++++-- .../public/services/use_case_service.ts | 35 ++++- src/plugins/workspace/public/types.ts | 2 +- src/plugins/workspace/public/utils.test.ts | 34 +++-- src/plugins/workspace/public/utils.ts | 12 +- 25 files changed, 661 insertions(+), 183 deletions(-) create mode 100644 changelogs/fragments/7703.yml create mode 100644 src/plugins/workspace/public/components/workspace_form/use_form_available_use_cases.test.ts create mode 100644 src/plugins/workspace/public/components/workspace_form/use_form_available_use_cases.ts create mode 100644 src/plugins/workspace/public/mocks.ts diff --git a/changelogs/fragments/7703.yml b/changelogs/fragments/7703.yml new file mode 100644 index 000000000000..721972dab4db --- /dev/null +++ b/changelogs/fragments/7703.yml @@ -0,0 +1,2 @@ +feat: +- [Workspaces]Add features in use case card and preselect first use case ([#7703](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7703)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx index 75d2cd0e11a3..914fa4751ff8 100644 --- a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx +++ b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx @@ -4,24 +4,17 @@ */ import React from 'react'; +import { IntlProvider } from 'react-intl'; import { render, screen, fireEvent } from '@testing-library/react'; +import { coreMock } from '../../../../../core/public/mocks'; +import { createMockedRegisteredUseCases$ } from '../../mocks'; + import { UseCaseFooter as UseCaseFooterComponent, UseCaseFooterProps } from './use_case_footer'; -import { coreMock, httpServiceMock } from '../../../../../core/public/mocks'; -import { IntlProvider } from 'react-intl'; -import { WorkspaceUseCase } from '../../types'; -import { CoreStart } from 'opensearch-dashboards/public'; -import { BehaviorSubject } from 'rxjs'; -import { WORKSPACE_USE_CASES } from '../../../common/constants'; describe('UseCaseFooter', () => { // let coreStartMock: CoreStart; const navigateToApp = jest.fn(); - const registeredUseCases$ = new BehaviorSubject([ - WORKSPACE_USE_CASES.observability, - WORKSPACE_USE_CASES['security-analytics'], - WORKSPACE_USE_CASES.essentials, - WORKSPACE_USE_CASES.search, - ]); + const registeredUseCases$ = createMockedRegisteredUseCases$(); const getMockCore = (isDashboardAdmin: boolean = true) => { const coreStartMock = coreMock.createStart(); diff --git a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx index 922cf3e66f7b..5a32d1534ce4 100644 --- a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx +++ b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx @@ -56,7 +56,7 @@ export const UseCaseFooter = ({ const closePopover = () => setPopover(false); const appId = - availableUseCases?.find((useCase) => useCase.id === useCaseId)?.features[0] ?? + availableUseCases?.find((useCase) => useCase.id === useCaseId)?.features[0].id ?? WORKSPACE_DETAIL_APP_ID; const filterWorkspaces = useMemo( diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx index f42665acd1d1..760c4060de58 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx @@ -5,15 +5,16 @@ import React from 'react'; import { PublicAppInfo } from 'opensearch-dashboards/public'; -import { fireEvent, render, waitFor, act } from '@testing-library/react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; import { BehaviorSubject } from 'rxjs'; +import { coreMock } from '../../../../../core/public/mocks'; +import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; +import { createMockedRegisteredUseCases$ } from '../../mocks'; + import { WorkspaceCreator as WorkspaceCreatorComponent, WorkspaceCreatorProps, } from './workspace_creator'; -import { coreMock } from '../../../../../core/public/mocks'; -import { createOpenSearchDashboardsReactContext } from '../../../../opensearch_dashboards_react/public'; -import { WORKSPACE_USE_CASES } from '../../../common/constants'; const workspaceClientCreate = jest .fn() @@ -96,12 +97,7 @@ const WorkspaceCreator = ({ }, }, }); - const registeredUseCases$ = new BehaviorSubject([ - WORKSPACE_USE_CASES.observability, - WORKSPACE_USE_CASES['security-analytics'], - WORKSPACE_USE_CASES.essentials, - WORKSPACE_USE_CASES.search, - ]); + const registeredUseCases$ = createMockedRegisteredUseCases$(); return ( @@ -139,33 +135,44 @@ describe('WorkspaceCreator', () => { it('should not create workspace when name is empty', async () => { const { getByTestId } = render(); - fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); - expect(workspaceClientCreate).not.toHaveBeenCalled(); - }); - it('should not create workspace with invalid name', async () => { - const { getByTestId } = render(); + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); + const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { - target: { value: '~' }, + target: { + value: '', + }, }); + fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); expect(workspaceClientCreate).not.toHaveBeenCalled(); }); - it('should not create workspace without use cases', async () => { - setHrefSpy.mockReset(); + it('should not create workspace with invalid name', async () => { const { getByTestId } = render(); + + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); + const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { - target: { value: 'test workspace name' }, + target: { value: '~' }, }); - expect(setHrefSpy).not.toHaveBeenCalled(); - fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); expect(workspaceClientCreate).not.toHaveBeenCalled(); }); it('cancel create workspace', async () => { const { findByText, getByTestId } = render(); + + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); fireEvent.click(getByTestId('workspaceForm-bottomBar-cancelButton')); await findByText('Discard changes?'); fireEvent.click(getByTestId('confirmModalConfirmButton')); @@ -174,6 +181,11 @@ describe('WorkspaceCreator', () => { it('create workspace with detailed information', async () => { const { getByTestId } = render(); + + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -214,6 +226,11 @@ describe('WorkspaceCreator', () => { it('should show danger toasts after create workspace failed', async () => { workspaceClientCreate.mockReturnValueOnce({ result: { id: 'failResult' }, success: false }); const { getByTestId } = render(); + + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -232,6 +249,11 @@ describe('WorkspaceCreator', () => { throw new Error(); }); const { getByTestId } = render(); + + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -247,6 +269,11 @@ describe('WorkspaceCreator', () => { it('create workspace with customized permissions', async () => { const { getByTestId } = render(); + + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -280,6 +307,11 @@ describe('WorkspaceCreator', () => { const { getByTestId, getByTitle, getByText } = render( ); + + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); fireEvent.input(nameInput, { target: { value: 'test workspace name' }, @@ -287,9 +319,7 @@ describe('WorkspaceCreator', () => { fireEvent.click(getByTestId('workspaceUseCase-observability')); fireEvent.click(getByTestId('workspaceForm-select-dataSource-addNew')); fireEvent.click(getByTestId('workspaceForm-select-dataSource-comboBox')); - await act(() => { - fireEvent.click(getByText('Select')); - }); + fireEvent.click(getByText('Select')); fireEvent.click(getByTitle(dataSourcesList[0].title)); fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx index 26bed213d142..a7a2b247914a 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx @@ -6,7 +6,6 @@ import React, { useCallback } from 'react'; import { EuiPage, EuiPageBody, EuiPageContent, euiPaletteColorBlind } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { useObservable } from 'react-use'; import { BehaviorSubject } from 'rxjs'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; @@ -19,6 +18,8 @@ import { DataSource } from '../../../common/types'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; import { WorkspaceUseCase } from '../../types'; import { WorkspaceFormData } from '../workspace_form/types'; +import { getUseCaseFeatureConfig } from '../../utils'; +import { useFormAvailableUseCases } from '../workspace_form/use_form_available_use_cases'; import { NavigationPublicPluginStart } from '../../../../../plugins/navigation/public'; export interface WorkspaceCreatorProps { @@ -26,6 +27,7 @@ export interface WorkspaceCreatorProps { } export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { + const { registeredUseCases$ } = props; const { services: { application, @@ -42,13 +44,24 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { navigationUI: NavigationPublicPluginStart['ui']; }>(); + const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; + const { isOnlyAllowEssential, availableUseCases } = useFormAvailableUseCases({ + savedObjects, + registeredUseCases$, + onlyAllowEssentialEnabled: true, + }); + + const defaultSelectedUseCase = availableUseCases?.[0]; const defaultWorkspaceFormValues: Partial = { color: euiPaletteColorBlind()[0], + ...(defaultSelectedUseCase + ? { + name: defaultSelectedUseCase.title, + features: [getUseCaseFeatureConfig(defaultSelectedUseCase.id)], + } + : {}), }; - const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; - const availableUseCases = useObservable(props.registeredUseCases$, []); - const handleWorkspaceFormSubmit = useCallback( async (data: WorkspaceFormSubmitData) => { let result; @@ -97,6 +110,13 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { [notifications?.toasts, http, application, workspaceClient] ); + const isFormReadyToRender = + application && + savedObjects && + // Default values only worked for component mount, should wait for isOnlyAllowEssential and availableUseCases loaded + isOnlyAllowEssential !== undefined && + availableUseCases !== undefined; + return ( { color="subdued" hasShadow={false} > - {application && savedObjects && ( + {isFormReadyToRender && ( { }, }); - const registeredUseCases$ = new BehaviorSubject([ - WORKSPACE_USE_CASES.observability, - WORKSPACE_USE_CASES['security-analytics'], - WORKSPACE_USE_CASES.essentials, - WORKSPACE_USE_CASES.search, - ]); + const registeredUseCases$ = createMockedRegisteredUseCases$(); + return ( { + disabled?: boolean; +} diff --git a/src/plugins/workspace/public/components/workspace_form/use_form_available_use_cases.test.ts b/src/plugins/workspace/public/components/workspace_form/use_form_available_use_cases.test.ts new file mode 100644 index 000000000000..45192c293e9f --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/use_form_available_use_cases.test.ts @@ -0,0 +1,140 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { renderHook } from '@testing-library/react-hooks'; +import { BehaviorSubject } from 'rxjs'; +import { WorkspaceUseCase } from '../../types'; +import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; +import { savedObjectsServiceMock } from '../../../../../core/public/mocks'; +import { getIsOnlyAllowEssentialUseCase } from '../../utils'; + +import { useFormAvailableUseCases } from './use_form_available_use_cases'; + +jest.mock('../../utils', () => ({ + getIsOnlyAllowEssentialUseCase: jest.fn(), +})); + +describe('useFormAvailableUseCases', () => { + const mockSavedObjectsClient = savedObjectsServiceMock.createStartContract(); + + const mockUseCases: WorkspaceUseCase[] = [ + { + id: 'useCase1', + title: 'Use Case 1', + description: 'Use Case 1 description', + systematic: false, + features: [], + }, + { + id: 'useCase2', + title: 'Use Case 2', + description: 'Use Case 2 description', + features: [], + systematic: true, + }, + { + ...DEFAULT_NAV_GROUPS.essentials, + features: [], + }, + { + ...DEFAULT_NAV_GROUPS.all, + features: [], + }, + ]; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return available use cases when onlyAllowEssentialEnabled is false', () => { + const registeredUseCases$ = new BehaviorSubject(mockUseCases); + const { result } = renderHook(() => + useFormAvailableUseCases({ + onlyAllowEssentialEnabled: false, + registeredUseCases$, + }) + ); + + expect(result.current.availableUseCases).toEqual([ + expect.objectContaining({ + id: 'useCase1', + title: 'Use Case 1', + systematic: false, + }), + expect.objectContaining(DEFAULT_NAV_GROUPS.essentials), + expect.objectContaining(DEFAULT_NAV_GROUPS.all), + ]); + }); + + it('should return only essential use case when onlyAllowEssentialEnabled is true', async () => { + const registeredUseCases$ = new BehaviorSubject(mockUseCases); + (getIsOnlyAllowEssentialUseCase as jest.Mock).mockResolvedValue(true); + + const { result, waitForNextUpdate } = renderHook(() => + useFormAvailableUseCases({ + onlyAllowEssentialEnabled: true, + savedObjects: mockSavedObjectsClient, + registeredUseCases$, + }) + ); + + await waitForNextUpdate(); + + expect(result.current.isOnlyAllowEssential).toBe(true); + expect(result.current.availableUseCases).toEqual([ + expect.objectContaining({ + ...DEFAULT_NAV_GROUPS.essentials, + disabled: true, + }), + ]); + }); + + it('should handle error when fetching isOnlyAllowEssential', async () => { + const registeredUseCases$ = new BehaviorSubject(mockUseCases); + (getIsOnlyAllowEssentialUseCase as jest.Mock).mockRejectedValue(new Error('Failed to fetch')); + + const { result, waitForNextUpdate } = renderHook(() => + useFormAvailableUseCases({ + onlyAllowEssentialEnabled: true, + savedObjects: mockSavedObjectsClient, + registeredUseCases$, + }) + ); + + await waitForNextUpdate(); + + expect(result.current.isOnlyAllowEssential).toBe(false); + expect(result.current.availableUseCases).toEqual([ + expect.objectContaining({ + id: 'useCase1', + title: 'Use Case 1', + systematic: false, + }), + expect.objectContaining(DEFAULT_NAV_GROUPS.essentials), + expect.objectContaining(DEFAULT_NAV_GROUPS.all), + ]); + }); + + it('should not update isOnlyAllowEssential after unmount', async () => { + const registeredUseCases$ = new BehaviorSubject(mockUseCases); + const getIsOnlyAllowEssentialUseCaseMock = (getIsOnlyAllowEssentialUseCase as jest.Mock).mockImplementation( + () => + new Promise((resolve) => { + setTimeout(() => resolve(false), 0); + }) + ); + const { unmount, result } = renderHook(() => + useFormAvailableUseCases({ + onlyAllowEssentialEnabled: true, + savedObjects: mockSavedObjectsClient, + registeredUseCases$, + }) + ); + + expect(result.current.isOnlyAllowEssential).toBeUndefined(); + unmount(); + await getIsOnlyAllowEssentialUseCaseMock.mock.results[0].value; + expect(result.current.isOnlyAllowEssential).toBeUndefined(); + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_form/use_form_available_use_cases.ts b/src/plugins/workspace/public/components/workspace_form/use_form_available_use_cases.ts new file mode 100644 index 000000000000..8aea12326173 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/use_form_available_use_cases.ts @@ -0,0 +1,71 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { useEffect, useMemo, useState } from 'react'; +import { useObservable } from 'react-use'; +import { BehaviorSubject } from 'rxjs'; + +import { ALL_USE_CASE_ID, DEFAULT_NAV_GROUPS, SavedObjectsStart } from '../../../../../core/public'; +import { WorkspaceUseCase } from '../../types'; +import { getIsOnlyAllowEssentialUseCase } from '../../utils'; +import { AvailableUseCaseItem } from './types'; + +interface UseFormAvailableUseCasesOptions { + onlyAllowEssentialEnabled?: boolean; + savedObjects?: SavedObjectsStart; + registeredUseCases$: BehaviorSubject; +} + +export const useFormAvailableUseCases = ({ + onlyAllowEssentialEnabled = false, + savedObjects, + registeredUseCases$, +}: UseFormAvailableUseCasesOptions) => { + const [isOnlyAllowEssential, setIsOnlyAllowEssential] = useState(); + const registeredUseCases = useObservable(registeredUseCases$, undefined); + + useEffect(() => { + let shouldUpdate = true; + if (!onlyAllowEssentialEnabled || !savedObjects) { + return; + } + const updateEssential = (payload: boolean) => { + if (shouldUpdate) { + setIsOnlyAllowEssential(payload); + } + }; + (async () => { + try { + const result = await getIsOnlyAllowEssentialUseCase(savedObjects.client); + updateEssential(result); + } catch (e) { + // Set to false if failed to fetch the "only allow essential use case" setting + updateEssential(false); + } + })(); + return () => { + shouldUpdate = false; + }; + }, [savedObjects, onlyAllowEssentialEnabled]); + + const availableUseCases = useMemo(() => { + if (!registeredUseCases) { + return undefined; + } + if (onlyAllowEssentialEnabled && isOnlyAllowEssential) { + return registeredUseCases.flatMap((useCase) => + useCase.id === DEFAULT_NAV_GROUPS.essentials.id ? [{ ...useCase, disabled: true }] : [] + ); + } + return registeredUseCases.filter( + (useCase) => !useCase.systematic || useCase.id === ALL_USE_CASE_ID + ); + }, [registeredUseCases, isOnlyAllowEssential, onlyAllowEssentialEnabled]); + + return { + isOnlyAllowEssential, + availableUseCases, + }; +}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx index fc4a669426b5..0bd172e6c47a 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx @@ -3,14 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - EuiColorPicker, - EuiCompressedFieldText, - EuiCompressedFormRow, - EuiSpacer, - EuiText, - EuiCompressedTextArea, -} from '@elastic/eui'; +import { EuiColorPicker, EuiCompressedFormRow, EuiSpacer, EuiText } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import React from 'react'; import { EuiColorPickerOutput } from '@elastic/eui/src/components/color_picker/color_picker'; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx index 05191dbd189a..66279a68a1b6 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx @@ -4,12 +4,12 @@ */ import React from 'react'; -import { render } from '@testing-library/react'; -import { WorkspaceForm } from './workspace_form'; +import { fireEvent, render } from '@testing-library/react'; import { coreMock } from '../../../../../core/public/mocks'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; -import { WORKSPACE_USE_CASES } from '../../../common/constants'; +import { createMockedRegisteredUseCases } from '../../mocks'; import { WorkspaceOperationType } from './constants'; +import { WorkspaceForm } from './workspace_form'; const mockCoreStart = coreMock.createStart(); @@ -41,7 +41,7 @@ const setup = ( application={application} savedObjects={savedObjects} operationType={WorkspaceOperationType.Create} - availableUseCases={[WORKSPACE_USE_CASES.essentials]} + availableUseCases={createMockedRegisteredUseCases()} dataSourceManagement={dataSourceManagement} /> ); @@ -61,9 +61,30 @@ describe('WorkspaceForm', () => { expect(queryByText('Associate data source')).not.toBeInTheDocument(); }); + it('should not display data source panel when data source is disabled', () => { const { queryByText } = setup(true, undefined); expect(queryByText('Associate data source')).not.toBeInTheDocument(); }); + + it('should automatic update workspace name after use case changed', () => { + const { getByTestId } = setup(false, mockDataSourceManagementSetup); + + const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); + expect(nameInput).toHaveValue(''); + fireEvent.click(getByTestId('workspaceUseCase-observability')); + expect(nameInput).toHaveValue('Observability'); + }); + + it('should not automatic update workspace name after manual input', () => { + const { getByTestId } = setup(false, mockDataSourceManagementSetup); + + const nameInput = getByTestId('workspaceForm-workspaceDetails-nameInputText'); + fireEvent.input(nameInput, { + target: { value: 'test workspace name' }, + }); + fireEvent.click(getByTestId('workspaceUseCase-observability')); + expect(nameInput).toHaveValue('test workspace name'); + }); }); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx index 8327bf39b951..f21a800a8357 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useRef } from 'react'; +import React, { useCallback, useRef } from 'react'; import { EuiPanel, EuiSpacer, EuiTitle, EuiForm, EuiText } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { WorkspaceFormProps } from './types'; @@ -29,7 +29,6 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { permissionEnabled, dataSourceManagement: isDataSourceEnabled, availableUseCases, - operationType, } = props; const { formId, @@ -40,15 +39,33 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { setDescription, handleFormSubmit, handleColorChange, - handleUseCaseChange, + handleUseCaseChange: handleUseCaseChangeInHook, setPermissionSettings, setSelectedDataSources, } = useWorkspaceForm(props); + const nameManualChangedRef = useRef(false); const disabledUserOrGroupInputIdsRef = useRef( defaultValues?.permissionSettings?.map((item) => item.id) ?? [] ); const isDashboardAdmin = application?.capabilities?.dashboards?.isDashboardAdmin ?? false; + const handleNameInputChange = useCallback( + (newName) => { + setName(newName); + nameManualChangedRef.current = true; + }, + [setName] + ); + const handleUseCaseChange = useCallback( + (newUseCase) => { + handleUseCaseChangeInHook(newUseCase); + const useCase = availableUseCases.find((item) => newUseCase === item.id); + if (!nameManualChangedRef.current && useCase) { + setName(useCase.title); + } + }, + [handleUseCaseChangeInHook, availableUseCases, setName] + ); return ( @@ -71,7 +88,7 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { color={formData.color} readOnly={!!defaultValues?.reserved} handleColorChange={handleColorChange} - onNameChange={setName} + onNameChange={handleNameInputChange} onDescriptionChange={setDescription} /> @@ -86,8 +103,6 @@ export const WorkspaceForm = (props: WorkspaceFormProps) => { onChange={handleUseCaseChange} formErrors={formErrors} availableUseCases={availableUseCases} - savedObjects={savedObjects} - operationType={operationType} /> diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx index 83bd8482f7d4..8a0b14782e91 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.test.tsx @@ -5,41 +5,31 @@ import React from 'react'; import { fireEvent, render, waitFor } from '@testing-library/react'; -import { WORKSPACE_USE_CASES } from '../../../common/constants'; +import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; import { WorkspaceUseCase, WorkspaceUseCaseProps } from './workspace_use_case'; import { WorkspaceFormErrors } from './types'; -import { coreMock } from '../../../../../core/public/mocks'; -import { WorkspaceOperationType } from './constants'; -import { getIsOnlyAllowEssentialUseCase } from '../../utils'; - -jest.mock('../../utils', () => ({ - getIsOnlyAllowEssentialUseCase: jest.fn().mockResolvedValue(false), -})); -const mockCoreStart = coreMock.createStart(); const setup = (options?: Partial) => { const onChangeMock = jest.fn(); const formErrors: WorkspaceFormErrors = {}; - const savedObjects = mockCoreStart.savedObjects; const renderResult = render( ); @@ -50,7 +40,7 @@ const setup = (options?: Partial) => { }; describe('WorkspaceUseCase', () => { - it('should render four use cases', () => { + it('should render passed use cases', () => { const { renderResult } = setup(); expect(renderResult.getByText('Observability')).toBeInTheDocument(); @@ -74,13 +64,87 @@ describe('WorkspaceUseCase', () => { fireEvent.click(renderResult.getByText('Observability')); expect(onChangeMock).not.toHaveBeenCalled(); }); - it('should only display essential use case when creating workspace if getIsOnlyAllowEssentialUseCase returns true', async () => { - (getIsOnlyAllowEssentialUseCase as jest.Mock).mockResolvedValue(true); - const { renderResult } = setup(); + it('should render disabled essential use case card', async () => { + const { renderResult } = setup({ + availableUseCases: [ + { + ...DEFAULT_NAV_GROUPS.essentials, + features: [], + disabled: true, + }, + ], + }); + await waitFor(() => { + expect(renderResult.getByText('Essentials')).toHaveClass( + 'euiCheckableCard__label-isDisabled' + ); + }); + }); + + it('should be able to toggle use case features', async () => { + const { renderResult } = setup({ + availableUseCases: [ + { + ...DEFAULT_NAV_GROUPS.observability, + features: [ + { id: 'feature1', title: 'Feature 1' }, + { id: 'feature2', title: 'Feature 2' }, + ], + }, + ], + }); + await waitFor(() => { + expect(renderResult.getByText('See more....')).toBeInTheDocument(); + expect(renderResult.queryByText('Feature 1')).toBe(null); + expect(renderResult.queryByText('Feature 2')).toBe(null); + }); + + fireEvent.click(renderResult.getByText('See more....')); + + await waitFor(() => { + expect(renderResult.getByText('See less....')).toBeInTheDocument(); + expect(renderResult.getByText('Feature 1')).toBeInTheDocument(); + expect(renderResult.getByText('Feature 2')).toBeInTheDocument(); + }); + + fireEvent.click(renderResult.getByText('See less....')); + + await waitFor(() => { + expect(renderResult.getByText('See more....')).toBeInTheDocument(); + expect(renderResult.queryByText('Feature 1')).toBe(null); + expect(renderResult.queryByText('Feature 2')).toBe(null); + }); + }); + + it('should show static all use case features', async () => { + const { renderResult } = setup({ + availableUseCases: [ + { + ...DEFAULT_NAV_GROUPS.all, + features: [ + { id: 'feature1', title: 'Feature 1' }, + { id: 'feature2', title: 'Feature 2' }, + ], + }, + ], + }); + + fireEvent.click(renderResult.getByText('See more....')); + await waitFor(() => { - expect(renderResult.queryByText('Essentials')).toBeInTheDocument(); - expect(renderResult.queryByText('Observability')).not.toBeInTheDocument(); + expect(renderResult.getByText('Discover')).toBeInTheDocument(); + expect(renderResult.getByText('Dashboards')).toBeInTheDocument(); + expect(renderResult.getByText('Visualize')).toBeInTheDocument(); + expect( + renderResult.getByText('Observability services, metrics, traces, and more') + ).toBeInTheDocument(); + expect( + renderResult.getByText('Security analytics threat alerts, findings, correlations, and more') + ).toBeInTheDocument(); + expect( + renderResult.getByText('Search studio, relevance tuning, vector search, and more') + ).toBeInTheDocument(); }); }); }); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx index 1a222238fc0c..24d1e7c80e64 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useCallback, useState, useEffect, useMemo } from 'react'; +import React, { useCallback, useState, useMemo } from 'react'; import { i18n } from '@osd/i18n'; import { EuiCheckableCard, @@ -11,34 +11,71 @@ import { EuiFlexItem, EuiCompressedFormRow, EuiText, + EuiLink, } from '@elastic/eui'; -import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; -import { WorkspaceUseCase as WorkspaceUseCaseObject } from '../../types'; -import { WorkspaceFormErrors } from './types'; +import { ALL_USE_CASE_ID, DEFAULT_NAV_GROUPS } from '../../../../../core/public'; +import { WorkspaceFormErrors, AvailableUseCaseItem } from './types'; import './workspace_use_case.scss'; -import type { SavedObjectsStart } from '../../../../../core/public'; -import { getIsOnlyAllowEssentialUseCase } from '../../utils'; -import { WorkspaceOperationType } from './constants'; interface WorkspaceUseCaseCardProps { id: string; title: string; checked: boolean; + disabled?: boolean; description: string; + features: Array<{ id: string; title?: string }>; onChange: (id: string) => void; } const WorkspaceUseCaseCard = ({ id, title, + features, description, checked, + disabled, onChange, }: WorkspaceUseCaseCardProps) => { + const [isExpanded, setIsExpanded] = useState(false); + const featureItems = useMemo(() => { + if (id === DEFAULT_NAV_GROUPS.essentials.id) { + return []; + } + if (id === ALL_USE_CASE_ID) { + return [ + i18n.translate('workspace.form.useCase.feature.all.discover', { + defaultMessage: 'Discover', + }), + i18n.translate('workspace.form.useCase.feature.all.dashboards', { + defaultMessage: 'Dashboards', + }), + i18n.translate('workspace.form.useCase.feature.all.visualize', { + defaultMessage: 'Visualize', + }), + i18n.translate('workspace.form.useCase.feature.all.observability', { + defaultMessage: 'Observability services, metrics, traces, and more', + }), + i18n.translate('workspace.form.useCase.feature.all.securityAnalytics', { + defaultMessage: 'Security analytics threat alerts, findings, correlations, and more', + }), + i18n.translate('workspace.form.useCase.feature.all.search', { + defaultMessage: 'Search studio, relevance tuning, vector search, and more', + }), + ]; + } + + const featureTitles = features.flatMap((feature) => (feature.title ? [feature.title] : [])); + return featureTitles; + }, [features, id]); + const handleChange = useCallback(() => { onChange(id); }, [id, onChange]); + const toggleExpanded = useCallback(() => { + setIsExpanded((flag) => !flag); + }, []); + return ( - - {description} - + {description} + {featureItems.length > 0 && ( + + {isExpanded && ( + <> + {i18n.translate('workspace.form.useCase.featureExpandedTitle', { + defaultMessage: 'Feature includes:', + })} +
    + {featureItems.map((feature, index) => ( +
  • {feature}
  • + ))} +
+ + )} + + + {isExpanded + ? i18n.translate('workspace.form.useCase.showLessButton', { + defaultMessage: 'See less....', + }) + : i18n.translate('workspace.form.useCase.showMoreButton', { + defaultMessage: 'See more....', + })} + + +
+ )}
); }; -type AvailableUseCase = Pick; - export interface WorkspaceUseCaseProps { value: string | undefined; onChange: (newValue: string) => void; formErrors: WorkspaceFormErrors; - availableUseCases: AvailableUseCase[]; - savedObjects: SavedObjectsStart; - operationType: WorkspaceOperationType; + availableUseCases: AvailableUseCaseItem[]; } export const WorkspaceUseCase = ({ @@ -73,32 +132,7 @@ export const WorkspaceUseCase = ({ onChange, formErrors, availableUseCases, - savedObjects, - operationType, }: WorkspaceUseCaseProps) => { - const [isOnlyAllowEssential, setIsOnlyAllowEssential] = useState(false); - - useEffect(() => { - if (operationType === WorkspaceOperationType.Create) { - getIsOnlyAllowEssentialUseCase(savedObjects.client).then((result: boolean) => { - setIsOnlyAllowEssential(result); - }); - } - }, [savedObjects, operationType]); - - const displayedUseCases = useMemo(() => { - let allAvailableUseCases = availableUseCases - .filter((item) => !item.systematic) - .concat(DEFAULT_NAV_GROUPS.all); - // When creating and isOnlyAllowEssential is true, only display essential use case - if (isOnlyAllowEssential && operationType === WorkspaceOperationType.Create) { - allAvailableUseCases = allAvailableUseCases.filter( - (item) => item.id === DEFAULT_NAV_GROUPS.essentials.id - ); - } - return allAvailableUseCases; - }, [availableUseCases, isOnlyAllowEssential, operationType]); - return ( - - {displayedUseCases.map(({ id, title, description }) => ( + + {availableUseCases.map(({ id, title, description, features, disabled }) => ( ))} diff --git a/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap b/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap index c85168003d76..3ead301fd7c2 100644 --- a/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap +++ b/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap @@ -691,7 +691,9 @@ exports[`WorkspaceList should render title and table normally 1`] = ` > + > + Search +
+ + + + + + + + ; } -interface EditorInstance { +export interface EditorInstance { TopBar: { Collapsed: () => React.ReactElement; Expanded: (() => React.ReactElement) | null; diff --git a/src/plugins/data/public/ui/query_editor/index.tsx b/src/plugins/data/public/ui/query_editor/index.tsx index 96584ebc9d8f..e852c8633550 100644 --- a/src/plugins/data/public/ui/query_editor/index.tsx +++ b/src/plugins/data/public/ui/query_editor/index.tsx @@ -30,3 +30,5 @@ export { QueryEditorExtensionDependencies, QueryEditorExtensionConfig, } from './query_editor_extensions'; + +export { createEditor, DefaultInput, DQLBody, SingleLineInput } from './editors'; diff --git a/src/plugins/data/public/ui/query_editor/language_selector.test.tsx b/src/plugins/data/public/ui/query_editor/language_selector.test.tsx index 62c4ebea288f..c3e477d5f7ee 100644 --- a/src/plugins/data/public/ui/query_editor/language_selector.test.tsx +++ b/src/plugins/data/public/ui/query_editor/language_selector.test.tsx @@ -8,25 +8,28 @@ import { QueryLanguageSelector } from './language_selector'; import { OpenSearchDashboardsContextProvider } from 'src/plugins/opensearch_dashboards_react/public'; import { coreMock } from '../../../../../core/public/mocks'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { QueryEnhancement } from '../types'; +import { Query } from '../..'; const startMock = coreMock.createStart(); jest.mock('../../services', () => ({ - getUiService: () => ({ - Settings: { - getAllQueryEnhancements: () => new Map(), - setUserQueryLanguage: jest.fn(), - setUiOverridesByUserQueryLanguage: jest.fn(), + getQueryService: () => ({ + queryString: { + getLanguageService: () => ({ + getLanguages: () => [ + { id: 'lucene', title: 'Lucene' }, + { id: 'kuery', title: 'DQL' }, + ], + getUserQueryLanguageBlocklist: () => [], + setUserQueryLanguage: jest.fn(), + }), + getUpdates$: () => ({ + subscribe: () => ({ + unsubscribe: jest.fn(), + }), + }), }, }), - getSearchService: () => ({ - __enhance: jest.fn(), - df: { - clear: jest.fn(), - }, - getDefaultSearchInterceptor: jest.fn(), - }), })); describe('LanguageSelector', () => { @@ -44,24 +47,22 @@ describe('LanguageSelector', () => { } it('should select lucene if language is lucene', () => { + const query: Query = { query: '', language: 'lucene' }; const component = mountWithIntl( wrapInContext({ - language: 'lucene', - onSelectLanguage: () => { - return; - }, + query, + onSelectLanguage: jest.fn(), }) ); expect(component).toMatchSnapshot(); }); it('should select DQL if language is kuery', () => { + const query: Query = { query: '', language: 'kuery' }; const component = mountWithIntl( wrapInContext({ - language: 'kuery', - onSelectLanguage: () => { - return; - }, + query, + onSelectLanguage: jest.fn(), }) ); expect(component).toMatchSnapshot(); diff --git a/src/plugins/data/public/ui/query_editor/language_selector.tsx b/src/plugins/data/public/ui/query_editor/language_selector.tsx index 455540d28df2..fd5d99dbebc9 100644 --- a/src/plugins/data/public/ui/query_editor/language_selector.tsx +++ b/src/plugins/data/public/ui/query_editor/language_selector.tsx @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import React, { useState, useEffect } from 'react'; import { PopoverAnchorPosition, EuiContextMenuPanel, @@ -10,78 +11,71 @@ import { EuiButtonEmpty, EuiContextMenuItem, } from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import React, { useState } from 'react'; -import { getUiService } from '../../services'; +import { getQueryService } from '../../services'; +import { LanguageConfig } from '../../query'; +import { Query } from '../..'; export interface QueryLanguageSelectorProps { - language: string; + query: Query; onSelectLanguage: (newLanguage: string) => void; anchorPosition?: PopoverAnchorPosition; appName?: string; } -const mapExternalLanguageToOptions = (language: string) => { +const mapExternalLanguageToOptions = (language: LanguageConfig) => { return { - label: language, - value: language, + label: language.title, + value: language.id, }; }; export const QueryLanguageSelector = (props: QueryLanguageSelectorProps) => { const [isPopoverOpen, setPopover] = useState(false); + const [currentLanguage, setCurrentLanguage] = useState(props.query.language); + + const queryString = getQueryService().queryString; + const languageService = queryString.getLanguageService(); + + useEffect(() => { + const subscription = queryString.getUpdates$().subscribe((query: Query) => { + if (query.language !== currentLanguage) { + setCurrentLanguage(query.language); + } + }); + + return () => { + subscription.unsubscribe(); + }; + }, [queryString, currentLanguage, props]); const onButtonClick = () => { setPopover(!isPopoverOpen); }; - const dqlLabel = i18n.translate('data.query.queryEditor.dqlLanguageName', { - defaultMessage: 'DQL', - }); - const luceneLabel = i18n.translate('data.query.queryEditor.luceneLanguageName', { - defaultMessage: 'Lucene', - }); + const languageOptions: Array<{ label: string; value: string }> = []; - const languageOptions = [ - { - label: dqlLabel, - value: 'kuery', - }, - { - label: luceneLabel, - value: 'lucene', - }, - ]; - - const uiService = getUiService(); - - const queryEnhancements = uiService.Settings.getAllQueryEnhancements(); - queryEnhancements.forEach((enhancement) => { + languageService.getLanguages().forEach((language) => { if ( - (enhancement.supportedAppNames && - props.appName && - !enhancement.supportedAppNames.includes(props.appName)) || - uiService.Settings.getUserQueryLanguageBlocklist().includes( - enhancement.language.toLowerCase() - ) + (language && props.appName && !language.editorSupportedAppNames?.includes(props.appName)) || + languageService.getUserQueryLanguageBlocklist().includes(language?.id) ) return; - languageOptions.unshift(mapExternalLanguageToOptions(enhancement.language)); + languageOptions.unshift(mapExternalLanguageToOptions(language!)); }); const selectedLanguage = { label: (languageOptions.find( - (option) => (option.value as string).toLowerCase() === props.language.toLowerCase() + (option) => (option.value as string).toLowerCase() === currentLanguage.toLowerCase() )?.label as string) ?? languageOptions[0].label, }; const handleLanguageChange = (newLanguage: string) => { + setCurrentLanguage(newLanguage); props.onSelectLanguage(newLanguage); - uiService.Settings.setUserQueryLanguage(newLanguage); }; - uiService.Settings.setUserQueryLanguage(props.language); + languageService.setUserQueryLanguage(currentLanguage); const languageOptionsMenu = languageOptions .sort((a, b) => { @@ -102,6 +96,7 @@ export const QueryLanguageSelector = (props: QueryLanguageSelectorProps) => { ); }); + return ( diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index 2238abbc5b1b..ccc616911ed8 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -8,19 +8,16 @@ import classNames from 'classnames'; import { isEqual } from 'lodash'; import React, { Component, createRef, RefObject } from 'react'; import { monaco } from '@osd/monaco'; -import { Settings } from '..'; import { IDataPluginServices, IFieldType, IIndexPattern, Query, TimeRange } from '../..'; import { OpenSearchDashboardsReactContextValue } from '../../../../opensearch_dashboards_react/public'; import { QuerySuggestion } from '../../autocomplete'; import { fromUser, getQueryLog, PersistedLog, toUser } from '../../query'; import { SuggestionsListSize } from '../typeahead/suggestions_component'; -import { DataSettings } from '../types'; import { QueryLanguageSelector } from './language_selector'; import { QueryEditorExtensions } from './query_editor_extensions'; import { QueryEditorBtnCollapse } from './query_editor_btn_collapse'; -import { SimpleDataSet } from '../../../common'; -import { createDQLEditor, createDefaultEditor } from './editors'; import { getQueryService, getIndexPatterns } from '../../services'; +import { DatasetSelector } from '../dataset_selector'; const LANGUAGE_ID_SQL = 'SQL'; monaco.languages.register({ id: LANGUAGE_ID_SQL }); @@ -29,10 +26,7 @@ const LANGUAGE_ID_KUERY = 'kuery'; monaco.languages.register({ id: LANGUAGE_ID_KUERY }); export interface QueryEditorProps { - dataSet?: SimpleDataSet; query: Query; - dataSetContainerRef?: React.RefCallback; - settings: Settings; disableAutoFocus?: boolean; screenTitle?: string; queryActions?: any; @@ -44,12 +38,10 @@ export interface QueryEditorProps { onChange?: (query: Query, dateRange?: TimeRange) => void; onChangeQueryEditorFocus?: (isFocused: boolean) => void; onSubmit?: (query: Query, dateRange?: TimeRange) => void; - getQueryStringInitialValue?: (language: string) => string; dataTestSubj?: string; size?: SuggestionsListSize; className?: string; isInvalid?: boolean; - queryLanguage?: string; headerClassName?: string; bannerClassName?: string; footerClassName?: string; @@ -70,18 +62,6 @@ interface State { lineCount: number | undefined; } -const KEY_CODES = { - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - ENTER: 13, - ESC: 27, - TAB: 9, - HOME: 36, - END: 35, -}; - // Needed for React.lazy // TODO: MQL export this and let people extended this // eslint-disable-next-line import/no-default-export @@ -98,19 +78,17 @@ export default class QueryEditorUI extends Component { public inputRef: monaco.editor.IStandaloneCodeEditor | null = null; - private queryService = getQueryService(); + private queryString = getQueryService().queryString; + private languageManager = this.queryString.getLanguageService(); private persistedLog: PersistedLog | undefined; private abortController?: AbortController; private services = this.props.opensearchDashboards.services; private headerRef: RefObject = createRef(); private bannerRef: RefObject = createRef(); - private extensionMap = this.props.settings?.getQueryEditorExtensionMap(); + private extensionMap = this.languageManager.getQueryEditorExtensionMap(); private getQueryString = () => { - if (!this.props.query.query) { - return this.props.getQueryStringInitialValue?.(this.props.query.language) ?? ''; - } return toUser(this.props.query.query); }; @@ -123,7 +101,7 @@ export default class QueryEditorUI extends Component { !( this.headerRef.current && this.bannerRef.current && - this.props.queryLanguage && + this.props.query.language && this.extensionMap && Object.keys(this.extensionMap).length > 0 ) @@ -132,7 +110,7 @@ export default class QueryEditorUI extends Component { } return ( { this.persistedLog.add(query.query); } - this.props.onSubmit({ query: fromUser(query.query), language: query.language }); + this.props.onSubmit({ + query: fromUser(query.query), + language: query.language, + dataset: query.dataset, + }); } }; private onChange = (query: Query, dateRange?: TimeRange) => { if (this.props.onChange) { - this.props.onChange({ query: fromUser(query.query), language: query.language }, dateRange); + this.props.onChange( + { query: fromUser(query.query), language: query.language, dataset: query.dataset }, + dateRange + ); } }; @@ -165,7 +150,11 @@ export default class QueryEditorUI extends Component { index: null, }); - this.onChange({ query: value, language: this.props.query.language }); + this.onChange({ + query: value, + language: this.props.query.language, + dataset: this.props.query.dataset, + }); }; private onInputChange = (value: string) => { @@ -185,37 +174,18 @@ export default class QueryEditorUI extends Component { }; // TODO: MQL consider moving language select language of setting search source here - private onSelectLanguage = (language: string) => { + private onSelectLanguage = (languageId: string) => { // Send telemetry info every time the user opts in or out of kuery // As a result it is important this function only ever gets called in the // UI component's change handler. this.services.http.post('/api/opensearch-dashboards/dql_opt_in_stats', { - body: JSON.stringify({ opt_in: language === 'kuery' }), + body: JSON.stringify({ opt_in: languageId === 'kuery' }), }); - const newQuery = { - query: this.props.getQueryStringInitialValue?.(language) ?? '', - language, - }; - - const enhancement = this.props.settings.getQueryEnhancements(newQuery.language); - const fields = enhancement?.fields; - const newSettings: DataSettings = { - userQueryLanguage: newQuery.language, - userQueryString: newQuery.query, - ...(fields && { uiOverrides: { fields } }), - }; - this.props.settings?.updateSettings(newSettings); + const newQuery = this.queryString.getInitialQueryByLanguage(languageId); - const dateRangeEnhancement = enhancement?.searchBar?.dateRange; - const dateRange = dateRangeEnhancement - ? { - from: dateRangeEnhancement.initialFrom!, - to: dateRangeEnhancement.initialTo!, - } - : undefined; - this.onChange(newQuery, dateRange); - this.onSubmit(newQuery, dateRange); + this.onChange(newQuery); + this.onSubmit(newQuery); }; private initPersistedLog = () => { @@ -239,6 +209,19 @@ export default class QueryEditorUI extends Component { } public componentDidUpdate(prevProps: Props) { + const prevQuery = prevProps.query; + + if (!isEqual(this.props.query.dataset, prevQuery.dataset)) { + if (this.inputRef) { + const newQuery = this.queryString.getInitialQuery(); + const newQueryString = newQuery.query; + if (this.inputRef.getValue() !== newQueryString) { + this.inputRef.setValue(newQueryString); + this.onSubmit(newQuery); + } + } + } + const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { this.onChange({ ...this.props.query, query: parsedQuery }); @@ -258,9 +241,10 @@ export default class QueryEditorUI extends Component { }; private fetchIndexPattern = async () => { - const dataSetTitle = this.queryService.dataSetManager.getDataSet()?.title; - if (!dataSetTitle) return undefined; - return getIndexPatterns().getByTitle(dataSetTitle); + const dataset = this.queryString.getQuery().dataset; + if (!dataset) return undefined; + const indexPattern = await getIndexPatterns().get(dataset.id); + return indexPattern; }; provideCompletionItems = async ( @@ -309,7 +293,7 @@ export default class QueryEditorUI extends Component { const languageSelector = ( { footerItems: { start: [ `${this.state.lineCount} ${this.state.lineCount === 1 ? 'line' : 'lines'}`, - this.props.dataSet?.timeFieldName || '', + this.props.query.dataset?.timeFieldName || '', ], }, provideCompletionItems: this.provideCompletionItems, @@ -343,7 +327,6 @@ export default class QueryEditorUI extends Component { onChange: (value: string) => { // Replace new lines with an empty string to prevent multi-line input this.onQueryStringChange(value.replace(/[\r\n]+/gm, '')); - this.setState({ lineCount: undefined }); }, editorDidMount: (editor: monaco.editor.IStandaloneCodeEditor) => { @@ -369,9 +352,11 @@ export default class QueryEditorUI extends Component { provideCompletionItems: this.provideCompletionItems, }; + const languageEditorFunc = this.languageManager.getLanguage(this.props.query.language)!.editor; + const languageEditor = useQueryEditor - ? createDefaultEditor(singleLineInputProps, {}, defaultInputProps) - : createDQLEditor(singleLineInputProps, singleLineInputProps, { + ? languageEditorFunc(singleLineInputProps, {}, defaultInputProps) + : languageEditorFunc(singleLineInputProps, singleLineInputProps, { filterBar: this.props.filterBar, }); @@ -393,7 +378,7 @@ export default class QueryEditorUI extends Component { onClick={() => this.setState({ isCollapsed: !this.state.isCollapsed })} isCollapsed={!this.state.isCollapsed} /> -
+
{this.state.isCollapsed ? languageEditor.TopBar.Collapsed() @@ -410,169 +395,6 @@ export default class QueryEditorUI extends Component {
{languageEditor.Body()}
)} - {/* - - - - this.setState({ isCollapsed: !this.state.isCollapsed })} - isCollapsed={!this.state.isCollapsed} - /> - - -
- - - - {(this.state.isCollapsed || !useQueryEditor) && ( - -
- -
-
- )} - {!useQueryEditor && ( - - - - )} -
-
- - {this.props.prepend} - - - - - - {!this.state.isCollapsed && useQueryEditor && ( - - )} - -
- - {languageSelector} - - - {this.state.lineCount} {this.state.lineCount === 1 ? 'line' : 'lines'} - - - {typeof this.props.indexPatterns?.[0] !== 'string' && - '@' + this.props.indexPatterns?.[0].timeFieldName} - - -
-
- - {!this.state.isCollapsed && ( - -
{this.props.filterBar}
-
- )} - */} {this.renderQueryEditorExtensions()}
); diff --git a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx index 4621944ecce3..0c15a551a3f8 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx @@ -13,7 +13,6 @@ import { prettyDuration, } from '@elastic/eui'; import classNames from 'classnames'; -import { isEqual } from 'lodash'; import React, { useState } from 'react'; import { createPortal } from 'react-dom'; import { IDataPluginServices, IIndexPattern, Query, TimeHistoryContract, TimeRange } from '../..'; @@ -23,18 +22,14 @@ import { } from '../../../../opensearch_dashboards_react/public'; import { UI_SETTINGS } from '../../../common'; import { getQueryLog, PersistedLog } from '../../query'; -import { Settings } from '../types'; import { NoDataPopover } from './no_data_popover'; import QueryEditorUI from './query_editor'; -import { useDataSetManager } from '../search_bar/lib/use_dataset_manager'; const QueryEditor = withOpenSearchDashboards(QueryEditorUI); // @internal export interface QueryEditorTopRowProps { query?: Query; - dataSetContainerRef?: React.RefCallback; - settings?: Settings; onSubmit: (payload: { dateRange: TimeRange; query?: Query }) => void; onChange: (payload: { dateRange: TimeRange; query?: Query }) => void; onRefresh?: (payload: { dateRange: TimeRange }) => void; @@ -71,31 +66,17 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { storage, appName, data: { - query: { dataSetManager: dataSetManager }, + query: { queryString }, }, } = opensearchDashboards.services; - const { dataSet } = useDataSetManager({ dataSetManager: dataSetManager! }); const queryLanguage = props.query && props.query.language; - const queryUiEnhancement = - (queryLanguage && - props.settings && - props.settings.getQueryEnhancements(queryLanguage)?.searchBar) || - null; - const parsedQuery = - !queryUiEnhancement || isValidQuery(props.query) - ? props.query! - : { query: getQueryStringInitialValue(queryLanguage!), language: queryLanguage! }; - if (!isEqual(parsedQuery?.query, props.query?.query)) { - onQueryChange(parsedQuery); - onSubmit({ query: parsedQuery, dateRange: getDateRange() }); - } const persistedLog: PersistedLog | undefined = React.useMemo( () => queryLanguage && uiSettings && storage && appName ? getQueryLog(uiSettings!, storage, appName, queryLanguage) : undefined, - [appName, queryLanguage, uiSettings, storage] + [queryLanguage, uiSettings, storage, appName] ); function onClickSubmitButton(event: React.MouseEvent) { @@ -109,16 +90,12 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { function getDateRange() { const defaultTimeSetting = uiSettings!.get(UI_SETTINGS.TIMEPICKER_TIME_DEFAULTS); return { - from: - props.dateRangeFrom || - queryUiEnhancement?.dateRange?.initialFrom || - defaultTimeSetting.from, - to: props.dateRangeTo || queryUiEnhancement?.dateRange?.initialTo || defaultTimeSetting.to, + from: props.dateRangeFrom || defaultTimeSetting.from, + to: props.dateRangeTo || defaultTimeSetting.to, }; } function onQueryChange(query: Query, dateRange?: TimeRange) { - if (queryUiEnhancement && !isValidQuery(query)) return; props.onChange({ query, dateRange: dateRange ?? getDateRange(), @@ -191,40 +168,21 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { return valueAsMoment.toISOString(); } - function isValidQuery(query: Query | undefined) { - if (query && query.query) return true; - } - - function getQueryStringInitialValue(language: string) { - const { settings } = props; - const input = settings?.getQueryEnhancements(language)?.searchBar?.queryStringInput - ?.initialValue; - - if (!input) return ''; - - return input.replace('', dataSet?.title ?? dataSet?.title ?? ''); - } - function renderQueryEditor() { if (!shouldRenderQueryEditor()) return; return ( @@ -248,14 +206,11 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { } function shouldRenderDatePicker(): boolean { - return Boolean( - (props.showDatePicker && (queryUiEnhancement?.showDatePicker ?? true)) ?? - (props.showAutoRefreshOnly && (queryUiEnhancement?.showAutoRefreshOnly ?? true)) - ); + return Boolean(props.showDatePicker ?? true) ?? (props.showAutoRefreshOnly && true); } function shouldRenderQueryEditor(): boolean { - return Boolean(props.showQueryEditor && props.settings && props.query && storage); + return Boolean(props.showQueryEditor && props.query && storage); } function renderUpdateButton() { @@ -270,6 +225,7 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { className="euiSuperUpdateButton" iconType="play" fill + size={'s'} > Run @@ -337,6 +293,7 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { dateFormat={uiSettings!.get('dateFormat')} isAutoRefreshOnly={props.showAutoRefreshOnly} className="osdQueryEditor__datePicker" + compressed={true} />
); diff --git a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx index 675f6cdc5791..b8671ea10559 100644 --- a/src/plugins/data/public/ui/search_bar/create_search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/create_search_bar.tsx @@ -29,7 +29,7 @@ */ import _ from 'lodash'; -import React, { useCallback, useEffect, useRef } from 'react'; +import React, { useEffect, useRef } from 'react'; import { CoreStart } from 'src/core/public'; import { OpenSearchDashboardsContextProvider } from '../../../../opensearch_dashboards_react/public'; import { QueryStart, SavedQuery } from '../../query'; @@ -40,14 +40,11 @@ import { useSavedQuery } from './lib/use_saved_query'; import { DataPublicPluginStart } from '../../types'; import { DataStorage, Filter, Query, TimeRange } from '../../../common'; import { useQueryStringManager } from './lib/use_query_string_manager'; -import { Settings } from '../types'; interface StatefulSearchBarDeps { core: CoreStart; data: Omit; storage: DataStorage; - settings: Settings; - setDataSetContainerRef: (ref: HTMLDivElement | null) => void; } export type StatefulSearchBarProps = SearchBarOwnProps & { @@ -132,13 +129,7 @@ const overrideDefaultBehaviors = (props: StatefulSearchBarProps) => { return props.useDefaultBehaviors ? {} : props; }; -export function createSearchBar({ - core, - storage, - data, - settings, - setDataSetContainerRef, -}: StatefulSearchBarDeps) { +export function createSearchBar({ core, storage, data }: StatefulSearchBarDeps) { // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. return (props: StatefulSearchBarProps) => { @@ -154,8 +145,7 @@ export function createSearchBar({ filterManager: data.query.filterManager, }); const { query } = useQueryStringManager({ - query: props.query, - queryStringManager: data.query.queryString, + queryString: data.query.queryString, }); const { timeRange, refreshInterval } = useTimefilter({ @@ -173,12 +163,6 @@ export function createSearchBar({ notifications: core.notifications, }); - const dataSetContainerRef = useCallback((node) => { - if (node) { - setDataSetContainerRef(node); - } - }, []); - // Fire onQuerySubmit on query or timerange change useEffect(() => { if (!useDefaultBehaviors || !onQuerySubmitRef.current) return; @@ -217,8 +201,6 @@ export function createSearchBar({ isRefreshPaused={refreshInterval.pause} filters={filters} query={query} - settings={settings} - dataSetContainerRef={dataSetContainerRef} onFiltersUpdated={defaultFiltersUpdated(data.query)} onRefreshChange={defaultOnRefreshChange(data.query)} savedQuery={savedQuery} diff --git a/src/plugins/data/public/ui/search_bar/index.tsx b/src/plugins/data/public/ui/search_bar/index.tsx index 41cc1c2a992b..6fffe20199e2 100644 --- a/src/plugins/data/public/ui/search_bar/index.tsx +++ b/src/plugins/data/public/ui/search_bar/index.tsx @@ -45,3 +45,4 @@ const WrappedSearchBar = (props: SearchBarProps) => ( export const SearchBar = injectI18n(withOpenSearchDashboards(WrappedSearchBar)); export { StatefulSearchBarProps } from './create_search_bar'; export type { SearchBarProps, SearchBarOwnProps } from './search_bar'; +export { useQueryStringManager } from './lib/use_query_string_manager'; diff --git a/src/plugins/data/public/ui/search_bar/lib/use_dataset_manager.ts b/src/plugins/data/public/ui/search_bar/lib/use_dataset_manager.ts deleted file mode 100644 index 7a92d03e9f33..000000000000 --- a/src/plugins/data/public/ui/search_bar/lib/use_dataset_manager.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { useState, useEffect } from 'react'; -import { Subscription } from 'rxjs'; -import { SimpleDataSet } from '../../../../../data/common'; -import { DataSetContract } from '../../../query'; - -interface UseDataSetManagerProps { - dataSet?: SimpleDataSet; - dataSetManager: DataSetContract; -} - -export const useDataSetManager = (props: UseDataSetManagerProps) => { - const [dataSet, setDataSet] = useState( - props.dataSet || props.dataSetManager.getDataSet() - ); - - useEffect(() => { - const subscriptions = new Subscription(); - - subscriptions.add( - props.dataSetManager.getUpdates$().subscribe({ - next: () => { - const newDataSet = props.dataSetManager.getDataSet(); - setDataSet(newDataSet); - }, - }) - ); - - return () => { - subscriptions.unsubscribe(); - }; - }, [dataSet, props.dataSet, props.dataSetManager]); - - return { dataSet }; -}; diff --git a/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts b/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts index b88bd282d442..8f9d49f80fef 100644 --- a/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts +++ b/src/plugins/data/public/ui/search_bar/lib/use_query_string_manager.ts @@ -28,35 +28,50 @@ * under the License. */ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { Subscription } from 'rxjs'; import { Query } from '../../..'; import { QueryStringContract } from '../../../query/query_string'; interface UseQueryStringProps { query?: Query; - queryStringManager: QueryStringContract; + queryString: QueryStringContract; } export const useQueryStringManager = (props: UseQueryStringProps) => { // Filters should be either what's passed in the initial state or the current state of the filter manager - const [query, setQuery] = useState(props.query || props.queryStringManager.getQuery()); + const [query, setQuery] = useState(() => props.query || props.queryString.getQuery()); + useEffect(() => { const subscriptions = new Subscription(); - subscriptions.add( - props.queryStringManager.getUpdates$().subscribe({ + props.queryString.getUpdates$().subscribe({ next: () => { - const newQuery = props.queryStringManager.getQuery(); - setQuery(newQuery); + setQuery((prevQuery) => { + const newQuery = props.queryString.getQuery(); + // Only update if the query has actually changed + return JSON.stringify(prevQuery) !== JSON.stringify(newQuery) ? newQuery : prevQuery; + }); }, }) ); - return () => { subscriptions.unsubscribe(); }; - }, [props.queryStringManager]); + }, [props.queryString]); + + // Use callback to memoize the function + const updateQuery = useCallback( + (newQueryPartial: Partial) => { + const updatedQuery = { ...query, ...newQueryPartial }; + props.queryString.setQuery(updatedQuery); + setQuery(updatedQuery); + }, + [query, props.queryString] + ); - return { query }; + return { + query, + updateQuery, + }; }; diff --git a/src/plugins/data/public/ui/search_bar/search_bar.test.tsx b/src/plugins/data/public/ui/search_bar/search_bar.test.tsx index 5e3532a15989..6721a91762ab 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.test.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.test.tsx @@ -30,6 +30,7 @@ import React from 'react'; import SearchBar from './search_bar'; +import { queryServiceMock } from '../../query/mocks'; import { OpenSearchDashboardsContextProvider } from 'src/plugins/opensearch_dashboards_react/public'; import { I18nProvider } from '@osd/i18n/react'; @@ -56,6 +57,24 @@ jest.mock('../query_string_input/query_bar_top_row', () => { return () =>
; }); +const mockQueryService = { + queryString: { + getLanguageService: () => ({ + getLanguage: () => ({ + fields: { + filterable: true, + }, + }), + }), + }, +}; + +// Update the mock for getQueryService +jest.mock('../../services', () => ({ + ...jest.requireActual('../../services'), + getQueryService: () => mockQueryService, +})); + const noop = jest.fn(); const createMockWebStorage = () => ({ @@ -110,6 +129,7 @@ function wrapSearchBarInContext(testProps: any) { storage: createMockStorage(), data: { query: { + ...queryServiceMock.createStartContract(false), savedQueries: {}, }, }, diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index fd8ff3dc21c1..891cf70379b2 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -44,7 +44,6 @@ import { FilterBar } from '../filter_bar/filter_bar'; import { QueryEditorTopRow } from '../query_editor'; import QueryBarTopRow from '../query_string_input/query_bar_top_row'; import { SavedQueryMeta, SaveQueryForm } from '../saved_query_form'; -import { Settings } from '../types'; import { FilterOptions } from '../filter_bar/filter_options'; interface SearchBarInjectedDeps { @@ -78,8 +77,6 @@ export interface SearchBarOwnProps { datePickerRef?: React.RefObject; // Query bar - should be in SearchBarInjectedDeps query?: Query; - settings?: Settings; - dataSetContainerRef?: React.RefCallback; // Show when user has privileges to save showSaveQuery?: boolean; savedQuery?: SavedQuery; @@ -119,8 +116,7 @@ class SearchBarUI extends Component { }; private services = this.props.opensearchDashboards.services; - private dataSetService = this.services.data.query.dataSetManager; - private queryStringService = this.services.data.query.queryString; + private queryStringManager = this.services.data.query.queryString; private savedQueryService = this.services.data.query.savedQueries; public filterBarRef: Element | null = null; public filterBarWrapperRef: Element | null = null; @@ -136,6 +132,7 @@ class SearchBarUI extends Component { nextQuery = { query: nextProps.query.query, language: nextProps.query.language, + dataset: nextProps.query.dataset, }; } else if ( nextProps.query && @@ -145,6 +142,17 @@ class SearchBarUI extends Component { nextQuery = { query: '', language: nextProps.query.language, + dataset: nextProps.query.dataset, + }; + } else if ( + nextProps.query && + prevState.query && + nextProps.query.dataset !== prevState.query.dataset + ) { + nextQuery = { + query: nextProps.query.query, + language: nextProps.query.language, + dataset: nextProps.query.dataset, }; } @@ -207,10 +215,6 @@ class SearchBarUI extends Component { ); }; - private supportsEnhancements() { - return this.props.settings?.supportsEnhancementsEnabled(this.services.appName); - } - private shouldRenderQueryEditor(isEnhancementsEnabledOverride: boolean) { // TODO: MQL handle no index patterns? if (!isEnhancementsEnabledOverride) return false; @@ -230,17 +234,19 @@ class SearchBarUI extends Component { return this.props.showQueryBar && (showDatePicker || showQueryInput); } - private shouldRenderFilterBar() { - // TODO: MQL handle no index patterns? + private shouldRenderFilterBar(isEnhancementsEnabledOverride: boolean) { + const language = this.queryStringManager + .getLanguageService() + .getLanguage(this.state.query?.language!); + const isFilterable = language?.fields?.filterable !== false; // Render if undefined or true + return ( this.props.showFilterBar && this.props.filters && (!this.useNewHeader || this.props.filters.length > 0) && this.props.indexPatterns && compact(this.props.indexPatterns).length > 0 && - (this.props.settings?.getQueryEnhancements(this.state.query?.language!)?.searchBar - ?.showFilterBar ?? - true) + (!isEnhancementsEnabledOverride || (isEnhancementsEnabledOverride && isFilterable)) ); } @@ -374,10 +380,10 @@ class SearchBarUI extends Component { } } ); - const dataSet = this.dataSetService.getDataSet(); - if (dataSet && queryAndDateRange.query) { - this.queryStringService.addToQueryHistory( - dataSet, + const dataset = this.queryStringManager.getQuery().dataset; + if (dataset && queryAndDateRange.query) { + this.queryStringManager.addToQueryHistory( + dataset, queryAndDateRange.query, queryAndDateRange.dateRange ); @@ -415,13 +421,11 @@ class SearchBarUI extends Component { public render() { const isEnhancementsEnabledOverride = - this.supportsEnhancements() && - this.services.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED); - - this.props.settings?.setUserQueryLanguageBlocklist( - this.services.uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE_BLOCKLIST) - ); - this.props.settings?.setUserQueryEnhancementsEnabled(isEnhancementsEnabledOverride); + this.services.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) && + this.queryStringManager + .getLanguageService() + .getLanguage(this.state.query?.language!) + ?.editorSupportedAppNames?.includes(this.services.appName); const searchBarMenu = (useSaveQueryMenu: boolean = false) => { return ( @@ -446,7 +450,7 @@ class SearchBarUI extends Component { }; let filterBar; - if (this.shouldRenderFilterBar()) { + if (this.shouldRenderFilterBar(isEnhancementsEnabledOverride)) { const filterGroupClasses = classNames('globalFilterGroup__wrapper', { // eslint-disable-next-line @typescript-eslint/naming-convention 'globalFilterGroup__wrapper-isVisible': this.state.isFiltersVisible, @@ -512,8 +516,6 @@ class SearchBarUI extends Component { queryEditor = ( ; - searchBar?: { - showDataSetsSelector?: boolean; - showDataSourcesSelector?: boolean; - showQueryInput?: boolean; - showFilterBar?: boolean; - showDatePicker?: boolean; - showAutoRefreshOnly?: boolean; - queryStringInput?: { - // will replace '' with the data source name - initialValue?: string; - }; - dateRange?: { - initialFrom?: string; - initialTo?: string; - }; - }; - fields?: { - filterable?: boolean; - visualizable?: boolean; - }; - showDocLinks?: boolean; - // List of supported app names that this enhancement should be enabled for, - // if not provided it will be enabled for all apps - supportedAppNames?: string[]; -} - -export interface UiEnhancements { - query?: QueryEnhancement; - queryEditorExtension?: QueryEditorExtensionConfig; -} - /** * The setup contract exposed by the Search plugin exposes the search strategy extension * point. */ -export interface IUiSetup { - __enhance: (enhancements: UiEnhancements) => void; -} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface IUiSetup {} /** * Data plugin prewired UI components */ export interface IUiStart { IndexPatternSelect: React.ComponentType; - /** - * @experimental - Subject to change - */ - DataSetNavigator: React.ComponentType; SearchBar: React.ComponentType; SuggestionsComponent: React.ComponentType; - /** - * @experimental - Subject to change - */ - Settings: Settings; - dataSetContainer$: Observable; } diff --git a/src/plugins/data/public/ui/ui_service.ts b/src/plugins/data/public/ui/ui_service.ts index 1802e3b79320..87cfcf630965 100644 --- a/src/plugins/data/public/ui/ui_service.ts +++ b/src/plugins/data/public/ui/ui_service.ts @@ -3,17 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { BehaviorSubject } from 'rxjs'; import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public'; import { ConfigSchema } from '../../config'; import { DataPublicPluginStart } from '../types'; -import { createDataSetNavigator } from './dataset_navigator'; import { createIndexPatternSelect } from './index_pattern_select'; -import { QueryEditorExtensionConfig } from './query_editor'; import { createSearchBar } from './search_bar/create_search_bar'; -import { createSettings } from './settings'; import { SuggestionsComponent } from './typeahead'; -import { IUiSetup, IUiStart, QueryEnhancement, UiEnhancements } from './types'; +import { IUiSetup, IUiStart } from './types'; import { DataStorage } from '../../common'; /** @internal */ @@ -28,9 +24,6 @@ export interface UiServiceStartDependencies { export class UiService implements Plugin { enhancementsConfig: ConfigSchema['enhancements']; - private queryEnhancements: Map = new Map(); - private queryEditorExtensionMap: Record = {}; - private dataSetContainer$ = new BehaviorSubject(null); constructor(initializerContext: PluginInitializerContext) { const { enhancements } = initializerContext.config.get(); @@ -39,52 +32,20 @@ export class UiService implements Plugin { } public setup(core: CoreSetup, {}: UiServiceSetupDependencies): IUiSetup { - return { - __enhance: (enhancements?: UiEnhancements) => { - if (!enhancements) return; - if (enhancements.query && enhancements.query.language) { - this.queryEnhancements.set(enhancements.query.language, enhancements.query); - } - if (enhancements.queryEditorExtension) { - this.queryEditorExtensionMap[enhancements.queryEditorExtension.id] = - enhancements.queryEditorExtension; - } - }, - }; + return {}; } public start(core: CoreStart, { dataServices, storage }: UiServiceStartDependencies): IUiStart { - const Settings = createSettings({ - config: this.enhancementsConfig, - search: dataServices.search, - storage, - queryEnhancements: this.queryEnhancements, - queryEditorExtensionMap: this.queryEditorExtensionMap, - }); - - const setDataSetContainerRef = (ref: HTMLDivElement | null) => { - this.dataSetContainer$.next(ref); - }; - const SearchBar = createSearchBar({ core, data: dataServices, storage, - settings: Settings, - setDataSetContainerRef, }); return { IndexPatternSelect: createIndexPatternSelect(core.savedObjects.client), - DataSetNavigator: createDataSetNavigator( - core.savedObjects.client, - core.http, - dataServices.query.dataSetManager - ), SearchBar, SuggestionsComponent, - Settings, - dataSetContainer$: this.dataSetContainer$, }; } diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index deb277087fcf..23ff1a283988 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -78,7 +78,6 @@ import { IDataFrame, IDataFrameResponse, createDataFrameCache, - dataFrameToSpec, } from '../../common'; type StrategyMap = Record>; @@ -214,30 +213,8 @@ export class SearchService implements Plugin { const dfService: DataFrameService = { get: () => this.dfCache.get(), - set: async (dataFrame: IDataFrame) => { - if (this.dfCache.get() && this.dfCache.get()?.name !== dataFrame.name) { - scopedIndexPatterns.clearCache(this.dfCache.get()!.name, false); - } - if ( - dataFrame.meta && - dataFrame.meta.queryConfig && - 'dataSource' in dataFrame.meta.queryConfig - ) { - const dataSource = await scopedIndexPatterns.findDataSourceByTitle( - dataFrame.meta.queryConfig.dataSource - ); - dataFrame.meta.queryConfig.dataSourceId = dataSource?.id; - } + set: (dataFrame: IDataFrame) => { this.dfCache.set(dataFrame); - const dataSetName = `${dataFrame.meta?.queryConfig?.dataSourceId ?? ''}.${ - dataFrame.name - }`; - const existingIndexPattern = await scopedIndexPatterns.get(dataSetName, true); - const dataSet = await scopedIndexPatterns.create( - dataFrameToSpec(dataFrame, existingIndexPattern?.id ?? dataSetName), - !existingIndexPattern?.id - ); - scopedIndexPatterns.saveToCache(dataSetName, dataSet); }, clear: () => { if (this.dfCache.get() === undefined) return; diff --git a/src/plugins/data_explorer/public/components/app_container.tsx b/src/plugins/data_explorer/public/components/app_container.tsx index b8749bf914e2..9326c4097f0f 100644 --- a/src/plugins/data_explorer/public/components/app_container.tsx +++ b/src/plugins/data_explorer/public/components/app_container.tsx @@ -54,7 +54,7 @@ export const AppContainer = React.memo( {isEnhancementsEnabled && ( { ), }, }, - ui: { - Settings: { - getEnabledQueryEnhancementsUpdated$: jest - .fn() - .mockImplementation(() => createObservable(false)), - }, - container$: jest.fn().mockImplementation(() => createObservable(null)), - }, }, notifications: { toasts: { @@ -67,6 +59,9 @@ jest.mock('../../../../opensearch_dashboards_react/public', () => { overlays: { openConfirm: jest.fn(), }, + uiSettings: { + get: jest.fn(), + }, }, }), withOpenSearchDashboards: () => (Component: React.ComponentClass) => (props: any) => ( diff --git a/src/plugins/data_explorer/public/components/sidebar/index.tsx b/src/plugins/data_explorer/public/components/sidebar/index.tsx index 616be16e9f56..430d70fa9180 100644 --- a/src/plugins/data_explorer/public/components/sidebar/index.tsx +++ b/src/plugins/data_explorer/public/components/sidebar/index.tsx @@ -3,10 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { EuiPageSideBar, EuiPortal, EuiSplitPanel } from '@elastic/eui'; +import React, { FC, useCallback, useEffect, useState } from 'react'; +import { EuiPageSideBar, EuiSplitPanel } from '@elastic/eui'; import { i18n } from '@osd/i18n'; -import { DataSource, DataSourceGroup, DataSourceSelectable } from '../../../../data/public'; +import { + DataSource, + DataSourceGroup, + DataSourceSelectable, + UI_SETTINGS, +} from '../../../../data/public'; import { DataSourceOption } from '../../../../data/public/'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { DataExplorerServices } from '../../types'; @@ -19,48 +24,21 @@ export const Sidebar: FC = ({ children }) => { const [selectedSources, setSelectedSources] = useState([]); const [dataSourceOptionList, setDataSourceOptionList] = useState([]); const [activeDataSources, setActiveDataSources] = useState([]); - const [isEnhancementsEnabled, setIsEnhancementsEnabled] = useState(false); - const containerRef = useRef(null); const { services: { - data: { indexPatterns, dataSources, ui }, + data: { indexPatterns, dataSources }, notifications: { toasts }, application, + uiSettings, }, } = useOpenSearchDashboards(); - const { DataSetNavigator } = ui; + const [isEnhancementEnabled, setIsEnhancementEnabled] = useState(false); useEffect(() => { - const subscriptions = ui.Settings.getEnabledQueryEnhancementsUpdated$().subscribe( - (enabledQueryEnhancements) => { - setIsEnhancementsEnabled(enabledQueryEnhancements); - } - ); - - return () => { - subscriptions.unsubscribe(); - }; - }, [ui.Settings]); - - const setContainerRef = useCallback((uiContainerRef) => { - uiContainerRef.appendChild(containerRef.current); - }, []); - - useEffect(() => { - if (!isEnhancementsEnabled) return; - const subscriptions = ui.dataSetContainer$.subscribe((dataSetContainer) => { - if (dataSetContainer === null) return; - if (containerRef.current) { - setContainerRef(dataSetContainer); - } - }); - - return () => { - subscriptions.unsubscribe(); - }; - }, [ui.dataSetContainer$, containerRef, setContainerRef, isEnhancementsEnabled]); + setIsEnhancementEnabled(uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED)); + }, [uiSettings]); useEffect(() => { let isMounted = true; @@ -144,16 +122,7 @@ export const Sidebar: FC = ({ children }) => { borderRadius="none" color="transparent" > - {isEnhancementsEnabled && ( - { - containerRef.current = node; - }} - > - - - )} - {!isEnhancementsEnabled && ( + {!isEnhancementEnabled && ( ; } const initialState: MetadataState = {}; @@ -20,12 +19,16 @@ export const getPreloadedState = async ({ embeddable, scopedHistory, data, + uiSettings, }: DataExplorerServices): Promise => { const { originatingApp } = embeddable .getStateTransfer(scopedHistory) .getIncomingEditorState({ keysToRemoveAfterFetch: ['id', 'input'] }) || {}; - const defaultIndexPattern = await data.indexPatterns.getDefault(); + const isQueryEnhancementEnabled = uiSettings.get(QUERY_ENHANCEMENT_ENABLED_SETTING); + const defaultIndexPattern = isQueryEnhancementEnabled + ? undefined + : await data.indexPatterns.getDefault(); const preloadedState: MetadataState = { ...initialState, originatingApp, @@ -39,12 +42,9 @@ export const slice = createSlice({ name: 'metadata', initialState, reducers: { - setIndexPattern: (state, action: PayloadAction) => { + setIndexPattern: (state, action: PayloadAction) => { state.indexPattern = action.payload; }, - setDataSet: (state, action: PayloadAction>) => { - state.dataSet = action.payload; - }, setOriginatingApp: (state, action: PayloadAction) => { state.originatingApp = action.payload; }, @@ -58,4 +58,4 @@ export const slice = createSlice({ }); export const { reducer } = slice; -export const { setIndexPattern, setDataSet, setOriginatingApp, setView, setState } = slice.actions; +export const { setIndexPattern, setOriginatingApp, setView, setState } = slice.actions; diff --git a/src/plugins/data_explorer/public/utils/state_management/redux_persistence.ts b/src/plugins/data_explorer/public/utils/state_management/redux_persistence.ts index 81517f3e9f4f..7eb715433f01 100644 --- a/src/plugins/data_explorer/public/utils/state_management/redux_persistence.ts +++ b/src/plugins/data_explorer/public/utils/state_management/redux_persistence.ts @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { Dataset, DEFAULT_DATA } from '../../../../data/common'; +import { QUERY_ENHANCEMENT_ENABLED_SETTING } from '../../components/constants'; import { DataExplorerServices } from '../../types'; import { getPreloadedState } from './preload'; import { RootState } from './store'; @@ -10,12 +12,49 @@ import { RootState } from './store'; export const loadReduxState = async (services: DataExplorerServices) => { try { const serializedState = services.osdUrlStateStorage.get('_a'); - if (serializedState !== null) return serializedState; + if (serializedState !== null) { + const isQueryEnhancementEnabled = services.uiSettings.get(QUERY_ENHANCEMENT_ENABLED_SETTING); + + // Migrate index pattern to query state + if (isQueryEnhancementEnabled && serializedState.metadata.indexPattern) { + const indexPattern = await services.data.indexPatterns.get( + serializedState.metadata.indexPattern + ); + + const dataset: Dataset = { + id: serializedState.metadata.indexPattern, + title: indexPattern.title, + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + }; + + if (indexPattern.dataSourceRef) { + const dataSource = await services.data.indexPatterns.getDataSource( + indexPattern.dataSourceRef.id + ); + + if (dataSource) { + dataset.dataSource = { + id: dataSource.id, + title: dataSource.attributes.title, + type: dataSource.attributes.dataSourceEngineType || '', + }; + } + } + services.data.query.queryString.setQuery({ + dataset, + }); + + delete serializedState.metadata.indexPattern; + } + + return serializedState; + } } catch (err) { // eslint-disable-next-line no-console console.error(err); } + // If state is not found, load the default state return await getPreloadedState(services); }; diff --git a/src/plugins/data_explorer/public/utils/state_management/store.ts b/src/plugins/data_explorer/public/utils/state_management/store.ts index 9d320de4b54b..daf0b3d7e369 100644 --- a/src/plugins/data_explorer/public/utils/state_management/store.ts +++ b/src/plugins/data_explorer/public/utils/state_management/store.ts @@ -116,4 +116,4 @@ export type RenderState = Omit; // Remaining state after export type Store = ReturnType; export type AppDispatch = Store['dispatch']; -export { MetadataState, setIndexPattern, setDataSet, setOriginatingApp } from './metadata_slice'; +export { MetadataState, setIndexPattern, setOriginatingApp } from './metadata_slice'; diff --git a/src/plugins/discover/public/application/utils/state_management/index.ts b/src/plugins/discover/public/application/utils/state_management/index.ts index e6df7e4774b8..989b2662f0d4 100644 --- a/src/plugins/discover/public/application/utils/state_management/index.ts +++ b/src/plugins/discover/public/application/utils/state_management/index.ts @@ -7,7 +7,6 @@ import { TypedUseSelectorHook } from 'react-redux'; import { RootState, setIndexPattern as updateIndexPattern, - setDataSet as updateDataSet, useTypedDispatch, useTypedSelector, } from '../../../../../data_explorer/public'; @@ -21,4 +20,4 @@ export interface DiscoverRootState extends RootState { export const useSelector: TypedUseSelectorHook = useTypedSelector; export const useDispatch = useTypedDispatch; -export { updateIndexPattern, updateDataSet }; +export { updateIndexPattern }; diff --git a/src/plugins/discover/public/application/view_components/canvas/index.tsx b/src/plugins/discover/public/application/view_components/canvas/index.tsx index 500c8ebdc80c..a44ac89c5d62 100644 --- a/src/plugins/discover/public/application/view_components/canvas/index.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/index.tsx @@ -3,15 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { i18n } from '@osd/i18n'; import React, { useEffect, useState, useRef, useCallback } from 'react'; -import { - EuiButtonIcon, - EuiContextMenu, - EuiPanel, - EuiPopover, - EuiCompressedSwitch, -} from '@elastic/eui'; +import { EuiPanel } from '@elastic/eui'; import { TopNav } from './top_nav'; import { ViewProps } from '../../../../../data_explorer/public'; import { DiscoverTable } from './discover_table'; @@ -33,7 +26,6 @@ import { import { OpenSearchSearchHit } from '../../../application/doc_views/doc_views_types'; import { buildColumns } from '../../utils/columns'; import './discover_canvas.scss'; -import { getNewDiscoverSetting, setNewDiscoverSetting } from '../../components/utils/local_storage'; import { HeaderVariant } from '../../../../../../core/public'; // eslint-disable-next-line import/no-default-export diff --git a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx index 8c4f748ca060..6cccc06cc0ee 100644 --- a/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx +++ b/src/plugins/discover/public/application/view_components/canvas/top_nav.tsx @@ -20,7 +20,6 @@ import { useDiscoverContext } from '../context'; import { useDispatch, setSavedQuery, useSelector } from '../../utils/state_management'; import './discover_canvas.scss'; -import { useDataSetManager } from '../utils/use_dataset_manager'; import { TopNavMenuItemRenderType } from '../../../../../navigation/public'; export interface TopNavProps { @@ -72,22 +71,22 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro useEffect(() => { let isMounted = true; - const initializeDataSet = async () => { + const initializeDataset = async () => { await data.indexPatterns.ensureDefaultIndexPattern(); const defaultIndexPattern = await data.indexPatterns.getDefault(); - const { dataSetManager } = data.query; - dataSetManager.initWithIndexPattern(defaultIndexPattern); - const defaultDataSet = dataSetManager.getDefaultDataSet(); + // TODO: ROCKY do we need this? + // const queryString = data.query.queryString; + // const defaultDataset = queryString.getDatasetService().getDefault(); if (!isMounted) return; setIndexPatterns(defaultIndexPattern ? [defaultIndexPattern] : undefined); - if (defaultDataSet) { - dataSetManager.setDataSet(defaultDataSet); - } + // if (defaultDataset) { + // datasetManager.setDataset(defaultDataset); + // } }; - initializeDataSet(); + initializeDataset(); return () => { isMounted = false; @@ -122,11 +121,12 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro dispatch(setSavedQuery(newSavedQueryId)); }; + const displayToNavLinkInPortal = + isEnhancementsEnabled && !!opts?.optionalRef?.topLinkRef?.current && !showActionsInGroup; + return ( <> - {isEnhancementsEnabled && - !!opts?.optionalRef?.topLinkRef?.current && - !showActionsInGroup && + {displayToNavLinkInPortal && createPortal( {topNavLinks.map((topNavLink) => ( @@ -147,7 +147,7 @@ export const TopNav = ({ opts, showSaveQuery, isEnhancementsEnabled }: TopNavPro )} { const { uiSettings, data } = services; - const queryDataSet = data.query.dataSetManager.getDataSet(); + const queryDataset = data.query.queryString.getQuery().dataset; - let dataSet = - indexPattern.id === queryDataSet?.id - ? await data.indexPatterns.get(queryDataSet?.id!, true) + const dataset = + indexPattern.id === queryDataset?.id + ? await data.indexPatterns.get(queryDataset?.id!, true) : indexPattern; - const dataFrame = searchSource?.getDataFrame(); - if ( - searchSource && - dataFrame && - dataFrame.name && - dataFrame.name !== '' && - dataSet.title !== dataFrame.name - ) { - dataSet = data.indexPatterns.getByTitle(dataFrame.name, true) ?? dataSet; - searchSource.setField('index', dataSet); - } const sortForSearchSource = getSortForSearchSource( sort, - dataSet, + dataset, uiSettings.get(SORT_DEFAULT_ORDER_SETTING) ); const size = uiSettings.get(SAMPLE_SIZE_SETTING); @@ -61,18 +50,18 @@ export const updateSearchSource = async ({ // searchSource which applies time range const timeRangeSearchSource = await data.search.searchSource.create(); const { isDefault } = indexPatternUtils; - if (isDefault(dataSet)) { + if (isDefault(dataset)) { const timefilter = data.query.timefilter.timefilter; timeRangeSearchSource.setField('filter', () => { - return timefilter.createFilter(dataSet); + return timefilter.createFilter(dataset); }); } searchSourceInstance.setParent(timeRangeSearchSource); searchSourceInstance.setFields({ - index: dataSet, + index: dataset, sort: sortForSearchSource, size, query: data.query.queryString.getQuery() || null, diff --git a/src/plugins/discover/public/application/view_components/utils/use_dataset_manager.ts b/src/plugins/discover/public/application/view_components/utils/use_dataset_manager.ts deleted file mode 100644 index f5698fc80929..000000000000 --- a/src/plugins/discover/public/application/view_components/utils/use_dataset_manager.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { useState, useEffect } from 'react'; -import { Subscription } from 'rxjs'; -import { DataSetManager } from '../../../../../data/public'; -import { SimpleDataSet } from '../../../../../data/common'; - -interface UseDataSetManagerProps { - dataSet?: SimpleDataSet; - dataSetManager: DataSetManager; -} - -export const useDataSetManager = (props: UseDataSetManagerProps) => { - const [dataSet, setDataSet] = useState( - props.dataSet || props.dataSetManager.getDataSet() - ); - - useEffect(() => { - const subscriptions = new Subscription(); - - subscriptions.add( - props.dataSetManager.getUpdates$().subscribe({ - next: () => { - const newDataSet = props.dataSetManager.getDataSet(); - setDataSet(newDataSet); - }, - }) - ); - - return () => { - subscriptions.unsubscribe(); - }; - }, [dataSet, props.dataSet, props.dataSetManager]); - - return { dataSet }; -}; diff --git a/src/plugins/discover/public/application/view_components/utils/use_index_pattern.ts b/src/plugins/discover/public/application/view_components/utils/use_index_pattern.ts index c03d3e6721e7..2f8bd6fbebf6 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_index_pattern.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_index_pattern.ts @@ -5,12 +5,10 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { i18n } from '@osd/i18n'; -import { SIMPLE_DATA_SET_TYPES, SimpleDataSet } from '../../../../../data/common'; -import { IndexPattern } from '../../../../../data/public'; +import { IndexPattern, useQueryStringManager } from '../../../../../data/public'; import { useSelector, updateIndexPattern } from '../../utils/state_management'; import { DiscoverViewServices } from '../../../build_services'; import { getIndexPatternId } from '../../helpers/get_index_pattern_id'; -import { useDataSetManager } from './use_dataset_manager'; import { QUERY_ENHANCEMENT_ENABLED_SETTING } from '../../../../common'; /** @@ -29,7 +27,9 @@ import { QUERY_ENHANCEMENT_ENABLED_SETTING } from '../../../../common'; */ export const useIndexPattern = (services: DiscoverViewServices) => { const { data, toastNotifications, uiSettings, store } = services; - const { dataSet } = useDataSetManager({ dataSetManager: data.query.dataSetManager }); + const { query } = useQueryStringManager({ + queryString: data.query.queryString, + }); const indexPatternIdFromState = useSelector((state) => state.metadata.indexPattern); const [indexPattern, setIndexPattern] = useState(undefined); const isQueryEnhancementEnabled = useMemo( @@ -41,41 +41,12 @@ export const useIndexPattern = (services: DiscoverViewServices) => { data.indexPatterns, ]); - const createTempIndexPattern = useCallback( - async (dataSetFromState: SimpleDataSet) => { - try { - const tempIndexPattern = await data.indexPatterns.create( - { - id: `${dataSetFromState.dataSourceRef?.id || ''}.${dataSetFromState.title}`, - title: dataSetFromState.title, - dataSourceRef: dataSetFromState.dataSourceRef, - type: dataSetFromState.type, - timeFieldName: dataSetFromState.timeFieldName, - fields: dataSetFromState.fields as any, - }, - true - ); - data.indexPatterns.saveToCache(tempIndexPattern.id!, tempIndexPattern); - return tempIndexPattern; - } catch (error) { - return null; - } - }, - [data.indexPatterns] - ); - useEffect(() => { let isMounted = true; const handleIndexPattern = async () => { - if (isQueryEnhancementEnabled && dataSet) { - let pattern; - - if (dataSet.type === SIMPLE_DATA_SET_TYPES.INDEX_PATTERN) { - pattern = await fetchIndexPatternDetails(dataSet.id); - } else { - pattern = await createTempIndexPattern(dataSet); - } + if (isQueryEnhancementEnabled && query?.dataset) { + const pattern = await data.indexPatterns.get(query.dataset.id); if (isMounted && pattern) { setIndexPattern(pattern); @@ -83,7 +54,11 @@ export const useIndexPattern = (services: DiscoverViewServices) => { } else if (!isQueryEnhancementEnabled) { if (!indexPatternIdFromState) { const indexPatternList = await data.indexPatterns.getCache(); - const newId = getIndexPatternId('', indexPatternList, uiSettings.get('defaultIndex')); + const newId = getIndexPatternId( + '', + indexPatternList || [], + uiSettings.get('defaultIndex') + ); if (isMounted) { store!.dispatch(updateIndexPattern(newId)); handleIndexPattern(); @@ -114,14 +89,13 @@ export const useIndexPattern = (services: DiscoverViewServices) => { }; }, [ isQueryEnhancementEnabled, - dataSet, indexPatternIdFromState, fetchIndexPatternDetails, - createTempIndexPattern, data.indexPatterns, store, toastNotifications, uiSettings, + query?.dataset, ]); return indexPattern; diff --git a/src/plugins/discover/public/application/view_components/utils/use_search.ts b/src/plugins/discover/public/application/view_components/utils/use_search.ts index 7e8095c5af30..b6c13d4982f2 100644 --- a/src/plugins/discover/public/application/view_components/utils/use_search.ts +++ b/src/plugins/discover/public/application/view_components/utils/use_search.ts @@ -118,8 +118,8 @@ export const useSearch = (services: DiscoverViewServices) => { const refetch$ = useMemo(() => new Subject(), []); const fetch = useCallback(async () => { - let dataSet = indexPattern; - if (!dataSet) { + let dataset = indexPattern; + if (!dataset) { data$.next({ status: shouldSearchOnPageLoad() ? ResultStatus.LOADING : ResultStatus.UNINITIALIZED, }); @@ -136,18 +136,18 @@ export const useSearch = (services: DiscoverViewServices) => { // Abort any in-progress requests before fetching again if (fetchStateRef.current.abortController) fetchStateRef.current.abortController.abort(); fetchStateRef.current.abortController = new AbortController(); - const histogramConfigs = dataSet.timeFieldName - ? createHistogramConfigs(dataSet, interval || 'auto', data) + const histogramConfigs = dataset.timeFieldName + ? createHistogramConfigs(dataset, interval || 'auto', data) : undefined; const searchSource = await updateSearchSource({ - indexPattern: dataSet, + indexPattern: dataset, services, sort, searchSource: savedSearch?.searchSource, histogramConfigs, }); - dataSet = searchSource.getField('index'); + dataset = searchSource.getField('index'); try { // Only show loading indicator if we are fetching when the rows are empty @@ -183,7 +183,7 @@ export const useSearch = (services: DiscoverViewServices) => { let bucketInterval = {}; let chartData; for (const row of rows) { - const fields = Object.keys(dataSet!.flattenHit(row)); + const fields = Object.keys(dataset!.flattenHit(row)); for (const fieldName of fields) { fetchStateRef.current.fieldCounts[fieldName] = (fetchStateRef.current.fieldCounts[fieldName] || 0) + 1; @@ -251,8 +251,7 @@ export const useSearch = (services: DiscoverViewServices) => { timefilter.getFetch$(), timefilter.getTimeUpdate$(), timefilter.getAutoRefreshFetch$(), - data.query.queryString.getUpdates$(), - data.query.dataSetManager.getUpdates$() + data.query.queryString.getUpdates$() ).pipe(debounceTime(100)); const subscription = fetch$.subscribe(() => { @@ -282,7 +281,6 @@ export const useSearch = (services: DiscoverViewServices) => { fetch, core.fatalErrors, shouldSearchOnPageLoad, - data.query.dataSetManager, ]); // Get savedSearch if it exists diff --git a/src/plugins/discover/public/plugin.ts b/src/plugins/discover/public/plugin.ts index 0c45fda15c49..3a083f05b805 100644 --- a/src/plugins/discover/public/plugin.ts +++ b/src/plugins/discover/public/plugin.ts @@ -202,7 +202,9 @@ export class DiscoverPlugin generateCb: (renderProps: any) => { const globalFilters: any = getServices().filterManager.getGlobalFilters(); const appFilters: any = getServices().filterManager.getAppFilters(); - const showDocLinks = getServices().data.ui.Settings.getUiOverrides().showDocLinks; + const showDocLinks = getServices() + .data.query.queryString.getLanguageService() + .getUiOverrides().showDocLinks; const hash = stringify( url.encodeQuery({ @@ -236,7 +238,9 @@ export class DiscoverPlugin defaultMessage: 'View single document', }), generateCb: (renderProps) => { - const showDocLinks = getServices().data.ui.Settings.getUiOverrides().showDocLinks; + const showDocLinks = getServices() + .data.query.queryString.getLanguageService() + .getUiOverrides().showDocLinks; const docUrl = `#/doc/${renderProps.indexPattern.id}/${ renderProps.hit._index diff --git a/src/plugins/opensearch_dashboards_utils/public/state_management/url/errors.ts b/src/plugins/opensearch_dashboards_utils/public/state_management/url/errors.ts index 87abbeff60b1..28fcbf5a6549 100644 --- a/src/plugins/opensearch_dashboards_utils/public/state_management/url/errors.ts +++ b/src/plugins/opensearch_dashboards_utils/public/state_management/url/errors.ts @@ -61,11 +61,13 @@ export const withNotifyOnErrors = (toasts: NotificationsStart['toasts']) => { return { onGetError: (error: Error) => { toasts.addError(error, { + id: 'opensearch_dashboards_utils.state_management.url.restoreUrlError', title: restoreUrlErrorTitle, }); }, onSetError: (error: Error) => { toasts.addError(error, { + id: 'opensearch_dashboards_utils.state_management.url.saveStateInUrlError', title: saveStateInUrlErrorTitle, }); }, diff --git a/src/plugins/query_enhancements/common/utils.ts b/src/plugins/query_enhancements/common/utils.ts index df300e92a413..208256bd4dd4 100644 --- a/src/plugins/query_enhancements/common/utils.ts +++ b/src/plugins/query_enhancements/common/utils.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { IDataFrame } from 'src/plugins/data/common'; +import { IDataFrame, Query } from 'src/plugins/data/common'; import { Observable, Subscription, from, throwError, timer } from 'rxjs'; import { catchError, concatMap, last, takeWhile, tap } from 'rxjs/operators'; import { FetchDataFrameContext, FetchFunction } from './types'; @@ -133,13 +133,9 @@ export const handleDataFrameError = (response: any) => { } }; -export const fetchDataFrame = ( - context: FetchDataFrameContext, - queryString: string, - df: IDataFrame -) => { +export const fetchDataFrame = (context: FetchDataFrameContext, query: Query, df: IDataFrame) => { const { http, path, signal } = context; - const body = JSON.stringify({ query: { qs: queryString, format: 'jdbc' }, df }); + const body = JSON.stringify({ query: { ...query, format: 'jdbc' }, df }); return from( http.fetch({ method: 'POST', diff --git a/src/plugins/query_enhancements/public/assets/s3_mark.svg b/src/plugins/query_enhancements/public/assets/s3_mark.svg new file mode 100644 index 000000000000..5b0c3a35aaad --- /dev/null +++ b/src/plugins/query_enhancements/public/assets/s3_mark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/plugins/query_enhancements/public/datasets/index.ts b/src/plugins/query_enhancements/public/datasets/index.ts new file mode 100644 index 000000000000..ddd7bf74995c --- /dev/null +++ b/src/plugins/query_enhancements/public/datasets/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './s3_handler'; diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/requests/index.tsx b/src/plugins/query_enhancements/public/datasets/requests/index.tsx similarity index 100% rename from src/plugins/data/public/ui/dataset_navigator/lib/requests/index.tsx rename to src/plugins/query_enhancements/public/datasets/requests/index.tsx diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/requests/sql.ts b/src/plugins/query_enhancements/public/datasets/requests/sql.ts similarity index 100% rename from src/plugins/data/public/ui/dataset_navigator/lib/requests/sql.ts rename to src/plugins/query_enhancements/public/datasets/requests/sql.ts diff --git a/src/plugins/query_enhancements/public/datasets/s3_handler.ts b/src/plugins/query_enhancements/public/datasets/s3_handler.ts new file mode 100644 index 000000000000..ce18662146bc --- /dev/null +++ b/src/plugins/query_enhancements/public/datasets/s3_handler.ts @@ -0,0 +1,113 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { DataStructure, Dataset, DatasetField } from 'src/plugins/data/common'; +import { DatasetTypeConfig } from 'src/plugins/data/public'; + +const S3_ICON = 'visTable'; +const S3_ID = 'S3'; + +export const s3TypeConfig: DatasetTypeConfig = { + id: S3_ID, + title: S3_ID, + meta: { + icon: { type: S3_ICON }, + tooltip: 'S3 Data Source', + }, + + toDataset: (path: DataStructure[]): Dataset => { + const s3 = path[path.length - 1]; + const dataSource = path.find((ds) => ds.type === S3_ID); + + return { + id: s3.id, + title: s3.title, + type: S3_ID, + dataSource: dataSource + ? { + id: dataSource.id, + title: dataSource.title, + type: dataSource.type, + } + : undefined, + }; + }, + + fetch: async ( + savedObjects: SavedObjectsClientContract, + path: DataStructure[] + ): Promise => { + const dataStructure = path[path.length - 1]; + switch (dataStructure.type) { + case S3_ID: + return { + ...dataStructure, + columnHeader: 'Connections', + hasNext: true, + children: [ + { + id: `${dataStructure.id}::mys3`, + title: 'mys3', + type: 'CONNECTION', + }, + ], + }; + case 'CONNECTION': + return { + ...dataStructure, + columnHeader: 'Databases', + hasNext: true, + children: [ + { + id: `${dataStructure.id}.defaultDb`, + title: 'defaultDb', + type: 'DATABASE', + }, + ], + }; + case 'DATABASE': + return { + ...dataStructure, + columnHeader: 'Tables', + hasNext: false, + children: [ + { + id: `${dataStructure.id}.table1`, + title: 'table1', + type: 'TABLE', + }, + { + id: `${dataStructure.id}.table2`, + title: 'table2', + type: 'TABLE', + }, + ], + }; + default: + const s3DataSources = await fetchS3DataSources(savedObjects); + return { + ...dataStructure, + columnHeader: 'S3 Data Sources', + hasNext: false, + children: s3DataSources, + }; + } + }, + + fetchFields: async (dataset: Dataset): Promise => { + // This is a placeholder. You'll need to implement the actual logic to fetch S3 fields. + // For now, we'll return an empty array. + return []; + }, + + supportedLanguages: (): string[] => { + return ['sql']; // Assuming S3 only supports SQL queries + }, +}; + +const fetchS3DataSources = async (client: SavedObjectsClientContract): Promise => { + return []; +}; diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/utils/query_session_utils.ts b/src/plugins/query_enhancements/public/datasets/utils/query_session_utils.ts similarity index 100% rename from src/plugins/data/public/ui/dataset_navigator/lib/utils/query_session_utils.ts rename to src/plugins/query_enhancements/public/datasets/utils/query_session_utils.ts diff --git a/src/plugins/query_enhancements/public/plugin.tsx b/src/plugins/query_enhancements/public/plugin.tsx index ccc00822c1a1..62f5270fa1b1 100644 --- a/src/plugins/query_enhancements/public/plugin.tsx +++ b/src/plugins/query_enhancements/public/plugin.tsx @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import moment from 'moment'; import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '../../../core/public'; import { IStorageWrapper, Storage } from '../../opensearch_dashboards_utils/public'; import { ConfigSchema } from '../common/config'; @@ -16,7 +15,9 @@ import { QueryEnhancementsPluginStart, QueryEnhancementsPluginStartDependencies, } from './types'; -import { UI_SETTINGS } from '../common'; +import { LanguageConfig, Query } from '../../data/public'; +import { s3TypeConfig } from './datasets'; +import { createEditor, DefaultInput, SingleLineInput } from '../../data/public'; export class QueryEnhancementsPlugin implements @@ -38,19 +39,7 @@ export class QueryEnhancementsPlugin core: CoreSetup, { data }: QueryEnhancementsPluginSetupDependencies ): QueryEnhancementsPluginSetup { - core.uiSettings.getUpdate$().subscribe(({ key, newValue }) => { - if (key === UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) { - if (newValue) { - core.uiSettings.set(UI_SETTINGS.STATE_STORE_IN_SESSION_STORAGE, true); - } - } - if (key === UI_SETTINGS.STATE_STORE_IN_SESSION_STORAGE) { - if (!newValue) { - core.uiSettings.set(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED, false); - } - } - }); - + const { queryString } = data.query; const pplSearchInterceptor = new PPLSearchInterceptor({ toasts: core.notifications.toasts, http: core.http, @@ -67,52 +56,43 @@ export class QueryEnhancementsPlugin usageCollector: data.search.usageCollector, }); - data.__enhance({ - ui: { - query: { - language: 'PPL', - search: pplSearchInterceptor, - searchBar: { - queryStringInput: { initialValue: 'source=' }, - dateRange: { - initialFrom: moment().subtract(2, 'days').toISOString(), - initialTo: moment().add(2, 'days').toISOString(), - }, - showFilterBar: false, - showDataSetsSelector: true, - showDataSourcesSelector: true, - }, - fields: { - filterable: false, - visualizable: false, - }, - showDocLinks: false, - supportedAppNames: ['discover'], - }, + const enhancedQueryEditor = createEditor(SingleLineInput, null, DefaultInput); + + // Register PPL language + const pplLanguageConfig: LanguageConfig = { + id: 'PPL', + title: 'PPL', + search: pplSearchInterceptor, + getQueryString: (query: Query) => { + return `source = ${query.dataset?.title}`; }, - }); + fields: { + filterable: false, + visualizable: false, + }, + showDocLinks: false, + editor: enhancedQueryEditor, + editorSupportedAppNames: ['discover'], + }; + queryString.getLanguageService().registerLanguage(pplLanguageConfig); - data.__enhance({ - ui: { - query: { - language: 'SQL', - search: sqlSearchInterceptor, - searchBar: { - showDatePicker: false, - showFilterBar: false, - showDataSetsSelector: true, - showDataSourcesSelector: true, - queryStringInput: { initialValue: 'SELECT * FROM LIMIT 10' }, - }, - fields: { - filterable: false, - visualizable: false, - }, - showDocLinks: false, - supportedAppNames: ['discover'], - }, + // Register SQL language + const sqlLanguageConfig: LanguageConfig = { + id: 'SQL', + title: 'SQL', + search: sqlSearchInterceptor, + getQueryString: (query: Query) => { + return `SELECT * FROM ${queryString.getQuery().dataset?.title} LIMIT 10`; }, - }); + fields: { + filterable: false, + visualizable: false, + }, + showDocLinks: false, + editor: enhancedQueryEditor, + editorSupportedAppNames: ['discover'], + }; + queryString.getLanguageService().registerLanguage(sqlLanguageConfig); data.__enhance({ ui: { @@ -120,6 +100,8 @@ export class QueryEnhancementsPlugin }, }); + queryString.getDatasetService().registerType(s3TypeConfig); + return {}; } diff --git a/src/plugins/query_enhancements/public/query_assist/components/query_assist_bar.tsx b/src/plugins/query_enhancements/public/query_assist/components/query_assist_bar.tsx index 4270177b7969..85f951fc7515 100644 --- a/src/plugins/query_enhancements/public/query_assist/components/query_assist_bar.tsx +++ b/src/plugins/query_enhancements/public/query_assist/components/query_assist_bar.tsx @@ -5,7 +5,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow } from '@elastic/eui'; import React, { SyntheticEvent, useEffect, useMemo, useRef, useState } from 'react'; -import { SimpleDataSet } from '../../../../data/common'; +import { Dataset } from '../../../../data/common'; import { IDataPluginServices, PersistedLog, @@ -26,6 +26,7 @@ interface QueryAssistInputProps { export const QueryAssistBar: React.FC = (props) => { const { services } = useOpenSearchDashboards(); + const queryString = services.data.query.queryString; const inputRef = useRef(null); const storage = getStorage(); const persistedLog: PersistedLog = useMemo( @@ -35,18 +36,18 @@ export const QueryAssistBar: React.FC = (props) => { const { generateQuery, loading } = useGenerateQuery(); const [callOutType, setCallOutType] = useState(); const dismissCallout = () => setCallOutType(undefined); - const [selectedDataSet, setSelectedDataSet] = useState( - services.data.query.dataSetManager.getDataSet() + const [selectedDataset, setSelectedDataset] = useState( + queryString.getQuery().dataset ); - const selectedIndex = selectedDataSet?.title; + const selectedIndex = selectedDataset?.title; const previousQuestionRef = useRef(); useEffect(() => { - const subscription = services.data.query.dataSetManager.getUpdates$().subscribe((dataSet) => { - setSelectedDataSet(dataSet); + const subscription = queryString.getUpdates$().subscribe((query) => { + setSelectedDataset(query.dataset); }); return () => subscription.unsubscribe(); - }, [services.data.query.dataSetManager]); + }, [queryString]); const onSubmit = async (e: SyntheticEvent) => { e.preventDefault(); @@ -65,7 +66,7 @@ export const QueryAssistBar: React.FC = (props) => { question: inputRef.current.value, index: selectedIndex, language: props.dependencies.language, - dataSourceId: selectedDataSet?.dataSourceRef?.id, + dataSourceId: selectedDataset?.dataSource?.id, }; const { response, error } = await generateQuery(params); if (error) { @@ -78,6 +79,7 @@ export const QueryAssistBar: React.FC = (props) => { services.data.query.queryString.setQuery({ query: response.query, language: params.language, + dataset: selectedDataset, }); if (response.timeRange) services.data.query.timefilter.timefilter.setTime(response.timeRange); setCallOutType('query_generated'); diff --git a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.test.tsx b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.test.tsx index cf99c79798b0..955fd8cd1569 100644 --- a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.test.tsx +++ b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.test.tsx @@ -6,12 +6,9 @@ import { firstValueFrom } from '@osd/std'; import { act, render, screen } from '@testing-library/react'; import React from 'react'; -import { of } from 'rxjs'; import { coreMock } from '../../../../../core/public/mocks'; -import { SimpleDataSet } from '../../../../data/common'; import { QueryEditorExtensionDependencies } from '../../../../data/public'; import { dataPluginMock } from '../../../../data/public/mocks'; -import { DataSetContract } from '../../../../data/public/query'; import { ConfigSchema } from '../../../common/config'; import { createQueryAssistExtension } from './create_extension'; @@ -24,25 +21,14 @@ const coreSetupMock = coreMock.createSetup({ }); const httpMock = coreSetupMock.http; const dataMock = dataPluginMock.createSetupContract(); -const dataSetMock = (dataMock.query.dataSetManager as unknown) as jest.Mocked; - -const mockSimpleDataSet = { - id: 'mock-data-set-id', - title: 'mock-title', - dataSourceRef: { - id: 'mock-data-source-id', - }, -} as SimpleDataSet; - -dataSetMock.getDataSet.mockReturnValue(mockSimpleDataSet); -dataSetMock.getUpdates$.mockReturnValue(of(mockSimpleDataSet)); jest.mock('../components', () => ({ QueryAssistBar: jest.fn(() =>
QueryAssistBar
), QueryAssistBanner: jest.fn(() =>
QueryAssistBanner
), })); -describe('CreateExtension', () => { +// TODO: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/7860 +describe.skip('CreateExtension', () => { const dependencies: QueryEditorExtensionDependencies = { language: 'PPL', onSelectLanguage: jest.fn(), diff --git a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx index b6a55fa3ebb6..f7614547c127 100644 --- a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx +++ b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx @@ -6,7 +6,7 @@ import { HttpSetup } from 'opensearch-dashboards/public'; import React, { useEffect, useState } from 'react'; import { distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators'; -import { SIMPLE_DATA_SOURCE_TYPES } from '../../../../data/common'; +import { DEFAULT_DATA } from '../../../../data/common'; import { DataPublicPluginSetup, QueryEditorExtensionConfig, @@ -25,15 +25,15 @@ const getAvailableLanguages$ = ( http: HttpSetup, data: DataPublicPluginSetup ) => - data.query.dataSetManager.getUpdates$().pipe( - startWith(data.query.dataSetManager.getDataSet()), + data.query.queryString.getUpdates$().pipe( + startWith(data.query.queryString.getQuery()), distinctUntilChanged(), - switchMap(async (simpleDataSet) => { + switchMap(async (query) => { // currently query assist tool relies on opensearch API to get index // mappings, external data source types (e.g. s3) are not supported - if (simpleDataSet?.dataSourceRef?.type === SIMPLE_DATA_SOURCE_TYPES.EXTERNAL) return []; + if (query.dataset?.dataSource?.type !== DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH) return []; - const dataSourceId = simpleDataSet?.dataSourceRef?.id; + const dataSourceId = query.dataset?.dataSource?.id; const cached = availableLanguagesByDataSource.get(dataSourceId); if (cached !== undefined) return cached; const languages = await http diff --git a/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts b/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts index 1f28df9af998..3a5edd67ca7f 100644 --- a/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts +++ b/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts @@ -5,16 +5,14 @@ import { trimEnd } from 'lodash'; import { Observable, throwError } from 'rxjs'; -import { catchError, concatMap } from 'rxjs/operators'; +import { catchError } from 'rxjs/operators'; import { DataFrameAggConfig, - getAggConfig, getRawDataFrame, - getRawQueryString, formatTimePickerDate, getUniqueValuesForRawAggs, updateDataFrameMeta, - getRawAggs, + Query, } from '../../../data/common'; import { DataPublicPluginStart, @@ -73,17 +71,17 @@ export class PPLSearchInterceptor extends SearchInterceptor { }; const getAggQsFn = ({ - qs, + query, aggConfig, timeField, timeFilter, }: { - qs: string; + query: Query; aggConfig: DataFrameAggConfig; timeField: any; timeFilter: string; }) => { - return removeKeyword(`${qs} ${getAggString(timeField, aggConfig)} ${timeFilter}`); + return removeKeyword(`${query.query} ${getAggString(timeField, aggConfig)} ${timeFilter}`); }; const getAggString = (timeField: any, aggsConfig?: DataFrameAggConfig) => { @@ -138,77 +136,24 @@ export class PPLSearchInterceptor extends SearchInterceptor { }; const dataFrame = getRawDataFrame(searchRequest); - - let queryString = dataFrame.meta?.queryConfig?.qs ?? getRawQueryString(searchRequest) ?? ''; - - dataFrame.meta = { - ...dataFrame.meta, - aggConfig: { - ...dataFrame.meta.aggConfig, - ...(getRawAggs(searchRequest) && - this.aggsService.types.get.bind(this) && - getAggConfig(searchRequest, {}, this.aggsService.types.get.bind(this))), - }, - queryConfig: { - ...dataFrame.meta.queryConfig, - ...(this.queryService.dataSetManager.getDataSet() && { - dataSourceId: this.queryService.dataSetManager.getDataSet()?.dataSourceRef?.id, - dataSourceName: this.queryService.dataSetManager.getDataSet()?.dataSourceRef?.name, - timeFieldName: this.queryService.dataSetManager.getDataSet()?.timeFieldName, - }), - }, - }; - - if (!dataFrame.schema) { - return fetchDataFrame(dfContext, queryString, dataFrame).pipe( - concatMap((response) => { - const df = response.body; - if (df.error) { - const jsError = new Error(df.error.response); - return throwError(jsError); - } - const timeField = dataFrame.meta?.queryConfig?.timeFieldName; - const aggConfig = dataFrame.meta?.aggConfig; - if (timeField && aggConfig) { - const timeFilter = getTimeFilter(timeField); - const newQuery = insertTimeFilter(queryString, timeFilter); - updateDataFrameMeta({ - dataFrame: df, - qs: newQuery, - aggConfig, - timeField, - timeFilter, - getAggQsFn: getAggQsFn.bind(this), - }); - return fetchDataFrame(dfContext, newQuery, df); - } - return fetchDataFrame(dfContext, queryString, df); - }), - catchError((error) => { - return throwError(error); - }) - ); - } - - if (dataFrame.schema) { - const timeField = dataFrame.meta?.queryConfig?.timeFieldName; - const aggConfig = dataFrame.meta?.aggConfig; - if (timeField && aggConfig) { - const timeFilter = getTimeFilter(timeField); - const newQuery = insertTimeFilter(queryString, timeFilter); - updateDataFrameMeta({ - dataFrame, - qs: newQuery, - aggConfig: dataFrame.meta?.aggConfig, - timeField, - timeFilter, - getAggQsFn: getAggQsFn.bind(this), - }); - queryString += timeFilter; - } + const query = this.queryService.queryString.getQuery(); + const timeField = query.dataset?.timeFieldName; + const aggConfig = dataFrame?.meta?.aggConfig; + if (timeField && aggConfig) { + const timeFilter = getTimeFilter(timeField); + const newQuery = insertTimeFilter(query.query as string, timeFilter); + updateDataFrameMeta({ + dataFrame, + query: { ...query, query: newQuery }, + aggConfig: dataFrame?.meta?.aggConfig, + timeField, + timeFilter, + getAggQsFn: getAggQsFn.bind(this), + }); + query.query += timeFilter; } - return fetchDataFrame(dfContext, queryString, dataFrame).pipe( + return fetchDataFrame(dfContext, query, dataFrame).pipe( catchError((error) => { return throwError(error); }) diff --git a/src/plugins/query_enhancements/public/search/sql_search_interceptor.ts b/src/plugins/query_enhancements/public/search/sql_search_interceptor.ts index cbd04f02a431..3225367df105 100644 --- a/src/plugins/query_enhancements/public/search/sql_search_interceptor.ts +++ b/src/plugins/query_enhancements/public/search/sql_search_interceptor.ts @@ -7,12 +7,7 @@ import { trimEnd } from 'lodash'; import { Observable, throwError } from 'rxjs'; import { i18n } from '@osd/i18n'; import { concatMap, map } from 'rxjs/operators'; -import { - DATA_FRAME_TYPES, - getRawDataFrame, - getRawQueryString, - SIMPLE_DATA_SET_TYPES, -} from '../../../data/common'; +import { DATA_FRAME_TYPES, getRawDataFrame } from '../../../data/common'; import { DataPublicPluginStart, IOpenSearchDashboardsSearchRequest, @@ -60,34 +55,7 @@ export class SQLSearchInterceptor extends SearchInterceptor { const dataFrame = getRawDataFrame(searchRequest); - const queryString = dataFrame.meta?.queryConfig?.qs ?? getRawQueryString(searchRequest) ?? ''; - - dataFrame.meta = { - ...dataFrame.meta, - queryConfig: { - ...dataFrame.meta.queryConfig, - ...(this.queryService.dataSetManager.getDataSet() && { - dataSourceId: this.queryService.dataSetManager.getDataSet()?.dataSourceRef?.id, - dataSourceName: this.queryService.dataSetManager.getDataSet()?.dataSourceRef?.name, - timeFieldName: this.queryService.dataSetManager.getDataSet()?.timeFieldName, - }), - }, - }; - - if (!dataFrame.schema) { - return fetchDataFrame(dfContext, queryString, dataFrame).pipe( - concatMap((response) => { - const df = response.body; - if (df.error) { - const jsError = new Error(df.error.response); - return throwError(jsError); - } - return fetchDataFrame(dfContext, queryString, df); - }) - ); - } - - return fetchDataFrame(dfContext, queryString, dataFrame); + return fetchDataFrame(dfContext, this.queryService.queryString.getQuery(), dataFrame); } protected runSearchAsync( @@ -104,22 +72,19 @@ export class SQLSearchInterceptor extends SearchInterceptor { }; const dataFrame = getRawDataFrame(searchRequest); - if (!dataFrame) { - return throwError(this.handleSearchError('DataFrame is not defined', request, signal!)); - } + const query = this.queryService.queryString.getQuery(); - const queryString = getRawQueryString(searchRequest) ?? ''; - const dataSourceRef = this.queryService.dataSetManager.getDataSet() + const dataSourceRef = query.dataset ? { - dataSourceId: this.queryService.dataSetManager.getDataSet()?.dataSourceRef?.id, - dataSourceName: this.queryService.dataSetManager.getDataSet()?.dataSourceRef?.name, + dataSourceId: query.dataset.dataSource?.id, + dataSourceName: query.dataset.dataSource?.title, } : {}; dataFrame.meta = { - ...dataFrame.meta, + ...dataFrame?.meta, queryConfig: { - ...dataFrame.meta.queryConfig, + ...dataFrame?.meta.queryConfig, ...dataSourceRef, }, sessionId: dataSourceRef ? getAsyncSessionId(dataSourceRef.dataSourceName!) : {}, @@ -158,7 +123,7 @@ export class SQLSearchInterceptor extends SearchInterceptor { defaultMessage: 'Starting query job...', }), }); - return fetchDataFrame(dfContext, queryString, dataFrame).pipe( + return fetchDataFrame(dfContext, query, dataFrame).pipe( concatMap((jobResponse) => { const df = jobResponse.body; if (dataSourceRef?.dataSourceName && df?.meta?.sessionId) { @@ -182,8 +147,8 @@ export class SQLSearchInterceptor extends SearchInterceptor { } public search(request: IOpenSearchDashboardsSearchRequest, options: ISearchOptions) { - const dataSet = this.queryService.dataSetManager.getDataSet(); - if (dataSet?.type === SIMPLE_DATA_SET_TYPES.TEMPORARY_ASYNC) { + const dataset = this.queryService.queryString.getQuery().dataset; + if (dataset?.type === 'S3') { return this.runSearchAsync(request, options.abortSignal, SEARCH_STRATEGY.SQL_ASYNC); } return this.runSearch(request, options.abortSignal, SEARCH_STRATEGY.SQL); diff --git a/src/plugins/query_enhancements/server/routes/index.ts b/src/plugins/query_enhancements/server/routes/index.ts index 8feaecc7b282..33896c9236cd 100644 --- a/src/plugins/query_enhancements/server/routes/index.ts +++ b/src/plugins/query_enhancements/server/routes/index.ts @@ -32,7 +32,9 @@ function defineRoute( validate: { body: schema.object({ query: schema.object({ - qs: schema.string(), + query: schema.string(), + language: schema.string(), + dataset: schema.nullable(schema.object({}, { unknowns: 'allow' })), format: schema.string(), }), df: schema.nullable(schema.object({}, { unknowns: 'allow' })), diff --git a/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts b/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts index 3d12448d58b0..95fa1ef6f537 100644 --- a/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts +++ b/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { first } from 'rxjs/operators'; import { SharedGlobalConfig, Logger, ILegacyClusterClient } from 'opensearch-dashboards/server'; import { Observable } from 'rxjs'; import { ISearchStrategy, getDefaultSearchParams, SearchUsage } from '../../../data/server'; @@ -13,6 +12,7 @@ import { IDataFrameResponse, IDataFrameWithAggs, IOpenSearchDashboardsSearchRequest, + Query, createDataFrame, } from '../../../data/common'; import { getFields } from '../../common/utils'; @@ -45,8 +45,6 @@ export const pplSearchStrategyProvider = ( const source = pipeMap.get('source'); - const searchQuery = query; - const filters = pipeMap.get('where'); const stats = pipeMap.get('stats'); @@ -55,15 +53,12 @@ export const pplSearchStrategyProvider = ( : undefined; return { - map: pipeMap, - search: searchQuery, aggs: aggsQuery, }; }; return { search: async (context, request: any, options) => { - const config = await config$.pipe(first()).toPromise(); const uiSettingsClient = await context.core.uiSettings.client; const { dataFrameHydrationStrategy, ...defaultParams } = await getDefaultSearchParams( @@ -71,14 +66,9 @@ export const pplSearchStrategyProvider = ( ); try { - const requestParams = parseRequest(request.body.query.qs); - const source = requestParams?.map.get('source'); - const { schema, meta } = request.body.df; - - request.body.query = - !schema || dataFrameHydrationStrategy === 'perQuery' - ? `source=${source} | head` - : requestParams.search; + const query: Query = request.body.query; + const { df } = request.body; + const rawResponse: any = await pplFacet.describeQuery(context, request); if (!rawResponse.success) { @@ -90,9 +80,9 @@ export const pplSearchStrategyProvider = ( } const dataFrame = createDataFrame({ - name: source, - schema: schema ?? rawResponse.data.schema, - meta, + name: query.dataset?.id, + schema: rawResponse.data.schema, + meta: df?.meta, fields: getFields(rawResponse), }); @@ -100,11 +90,10 @@ export const pplSearchStrategyProvider = ( if (usage) usage.trackSuccess(rawResponse.took); - if (dataFrame.meta?.aggsQs) { - for (const [key, aggQueryString] of Object.entries(dataFrame.meta.aggsQs)) { + if (dataFrame?.meta?.aggsQs) { + for (const [key, aggQueryString] of Object.entries(dataFrame?.meta?.aggsQs)) { const aggRequest = parseRequest(aggQueryString as string); - const query = aggRequest.aggs; - request.body.query = query; + request.body.query = aggRequest.aggs; const rawAggs: any = await pplFacet.describeQuery(context, request); (dataFrame as IDataFrameWithAggs).aggs = {}; (dataFrame as IDataFrameWithAggs).aggs[key] = rawAggs.data.datarows?.map((hit: any) => { diff --git a/src/plugins/query_enhancements/server/search/sql_async_search_strategy.ts b/src/plugins/query_enhancements/server/search/sql_async_search_strategy.ts index 1a76dbf85dd9..ea292c1a3218 100644 --- a/src/plugins/query_enhancements/server/search/sql_async_search_strategy.ts +++ b/src/plugins/query_enhancements/server/search/sql_async_search_strategy.ts @@ -12,6 +12,7 @@ import { IDataFrameResponse, IOpenSearchDashboardsSearchRequest, PartialDataFrame, + Query, createDataFrame, } from '../../../data/common'; import { Facet } from '../utils'; @@ -33,13 +34,14 @@ export const sqlAsyncSearchStrategyProvider = ( return { search: async (context, request: any, options) => { try { + const query: Query = request?.body?.query; // Create job: this should return a queryId and sessionId - if (request?.body?.query?.qs) { + if (query) { const df = request.body?.df; request.body = { - query: request.body.query.qs, - datasource: df?.meta?.queryConfig?.dataSourceName, - lang: 'sql', + query: query.query, + datasource: query.dataset?.dataSource?.title, + lang: SEARCH_STRATEGY.SQL, sessionId: df?.meta?.sessionId, }; const rawResponse: any = await sqlAsyncFacet.describeQuery(context, request); @@ -55,12 +57,13 @@ export const sqlAsyncSearchStrategyProvider = ( const sessionId = rawResponse.data?.sessionId; const partial: PartialDataFrame = { - ...request.body.df, + ...df, fields: rawResponse?.data?.schema || [], }; const dataFrame = createDataFrame(partial); dataFrame.meta = { - query: request.body.query, + ...dataFrame?.meta, + query: query.query, queryId, sessionId, }; @@ -87,6 +90,7 @@ export const sqlAsyncSearchStrategyProvider = ( dataFrame.size = asyncResponse?.data?.datarows?.length || 0; dataFrame.meta = { + ...dataFrame?.meta, status, queryId, error: status === 'FAILED' && asyncResponse.data?.error, diff --git a/src/plugins/query_enhancements/server/search/sql_search_strategy.ts b/src/plugins/query_enhancements/server/search/sql_search_strategy.ts index 4566e49b0664..f95a032b3f1e 100644 --- a/src/plugins/query_enhancements/server/search/sql_search_strategy.ts +++ b/src/plugins/query_enhancements/server/search/sql_search_strategy.ts @@ -27,7 +27,6 @@ export const sqlSearchStrategyProvider = ( return { search: async (context, request: any, _options) => { try { - request.body.query = request.body.query.qs; const rawResponse: any = await sqlFacet.describeQuery(context, request); if (!rawResponse.success) { diff --git a/src/plugins/query_enhancements/server/utils/facet.ts b/src/plugins/query_enhancements/server/utils/facet.ts index a6f23efba2a1..8ade2ae020ec 100644 --- a/src/plugins/query_enhancements/server/utils/facet.ts +++ b/src/plugins/query_enhancements/server/utils/facet.ts @@ -6,6 +6,7 @@ import { Logger } from 'opensearch-dashboards/server'; import { FacetResponse, IPPLEventsDataSource, IPPLVisualizationDataSource } from '../types'; import { shimSchemaRow, shimStats } from '.'; +import { Query } from '../../../data/common'; export interface FacetProps { client: any; @@ -36,14 +37,15 @@ export class Facet { endpoint: string ): Promise => { try { - const { format, df, ...query } = request.body; + const query: Query = request.body.query; + const { format, df } = request.body; const params = { body: { ...query }, ...(format !== 'jdbc' && { format }), }; - const dataSourceId = df?.meta?.queryConfig?.dataSourceId; - const client = dataSourceId - ? context.dataSource.opensearch.legacy.getClient(dataSourceId).callAPI + const clientId = query.dataset?.dataSource?.id ?? df?.meta?.queryConfig?.dataSourceId; + const client = clientId + ? context.dataSource.opensearch.legacy.getClient(clientId).callAPI : this.defaultClient.asScoped(request).callAsCurrentUser; const queryRes = await client(endpoint, params); return { From d7a8cb4c48458c10aa5cccd58b6d3ab4b2b83c52 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:39:27 -0700 Subject: [PATCH 246/276] chore: Update oui to 1.12 (#7865) (#7868) (cherry picked from commit 727c4791731c4e93bc60452b38bfa90e7d4a4ced) Signed-off-by: Viraj Sanghvi Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7865.yml | 2 ++ package.json | 2 +- packages/osd-ui-framework/package.json | 2 +- packages/osd-ui-shared-deps/package.json | 2 +- .../plugins/osd_tp_run_pipeline/package.json | 2 +- .../plugins/osd_sample_panel_action/package.json | 2 +- .../plugins/osd_tp_custom_visualizations/package.json | 2 +- yarn.lock | 8 ++++---- 8 files changed, 12 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/7865.yml diff --git a/changelogs/fragments/7865.yml b/changelogs/fragments/7865.yml new file mode 100644 index 000000000000..13c993e56f94 --- /dev/null +++ b/changelogs/fragments/7865.yml @@ -0,0 +1,2 @@ +chore: +- Update oui to 1.12 ([#7865](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7865)) \ No newline at end of file diff --git a/package.json b/package.json index 283cd8b5bfcb..952a5aa08af9 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "dependencies": { "@aws-crypto/client-node": "^3.1.1", "@elastic/datemath": "5.0.3", - "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.12.0", "@elastic/good": "^9.0.1-kibana3", "@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0", "@elastic/request-crypto": "2.0.0", diff --git a/packages/osd-ui-framework/package.json b/packages/osd-ui-framework/package.json index a2df7f94869f..e3176f43656e 100644 --- a/packages/osd-ui-framework/package.json +++ b/packages/osd-ui-framework/package.json @@ -23,7 +23,7 @@ "enzyme-adapter-react-16": "^1.9.1" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.12.0", "@osd/babel-preset": "1.0.0", "@osd/optimizer": "1.0.0", "comment-stripper": "^0.0.4", diff --git a/packages/osd-ui-shared-deps/package.json b/packages/osd-ui-shared-deps/package.json index 4f3af509c5b0..9162d4e4af31 100644 --- a/packages/osd-ui-shared-deps/package.json +++ b/packages/osd-ui-shared-deps/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@elastic/charts": "31.1.0", - "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.12.0", "@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0", "@opensearch/datemath": "5.0.3", "@osd/i18n": "1.0.0", diff --git a/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json b/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json index 6829659c99c6..416c31d22b7c 100644 --- a/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json +++ b/test/interpreter_functional/plugins/osd_tp_run_pipeline/package.json @@ -12,7 +12,7 @@ "build": "../../../../scripts/use_node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.12.0", "@osd/plugin-helpers": "1.0.0", "react": "^16.14.0", "react-dom": "^16.12.0", diff --git a/test/plugin_functional/plugins/osd_sample_panel_action/package.json b/test/plugin_functional/plugins/osd_sample_panel_action/package.json index 941ed8daab99..6a9567cb1967 100644 --- a/test/plugin_functional/plugins/osd_sample_panel_action/package.json +++ b/test/plugin_functional/plugins/osd_sample_panel_action/package.json @@ -12,7 +12,7 @@ "build": "../../../../scripts/use_node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.12.0", "react": "^16.14.0", "typescript": "4.0.2" } diff --git a/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json b/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json index 74596d89543f..8b0b24a07f4b 100644 --- a/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json +++ b/test/plugin_functional/plugins/osd_tp_custom_visualizations/package.json @@ -12,7 +12,7 @@ "build": "../../../../scripts/use_node ../../../../scripts/remove.js './target' && tsc" }, "devDependencies": { - "@elastic/eui": "npm:@opensearch-project/oui@1.11.0", + "@elastic/eui": "npm:@opensearch-project/oui@1.12.0", "@osd/plugin-helpers": "1.0.0", "react": "^16.14.0", "typescript": "4.0.2" diff --git a/yarn.lock b/yarn.lock index 32094d3da561..2fa99056db46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1431,10 +1431,10 @@ resolved "https://registry.yarnpkg.com/@elastic/eslint-plugin-eui/-/eslint-plugin-eui-0.0.2.tgz#56b9ef03984a05cc213772ae3713ea8ef47b0314" integrity sha512-IoxURM5zraoQ7C8f+mJb9HYSENiZGgRVcG4tLQxE61yHNNRDXtGDWTZh8N1KIHcsqN1CEPETjuzBXkJYF/fDiQ== -"@elastic/eui@npm:@opensearch-project/oui@1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@opensearch-project/oui/-/oui-1.11.0.tgz#48df25feabd1da5c6eadd92e0172ee32cacb7588" - integrity sha512-6E6tu/j5bH5odQSjCvcR++SQme/vSGZFeMQmcbB7a0LzCRYoExNj+gt5DgnR1+PRkuRKmaHx8wYrAS1GELp82A== +"@elastic/eui@npm:@opensearch-project/oui@1.12.0": + version "1.12.0" + resolved "https://registry.yarnpkg.com/@opensearch-project/oui/-/oui-1.12.0.tgz#dfb34669549fec2500e71f66e43868932178318c" + integrity sha512-0phXBR8OZneJr/TwIiqTMWL53e/2PqzEDzl/y7QYEc6xUofD+RQSNi/YZNw4OZgscogu/zTajWA5tdQdrxT2+g== dependencies: "@types/chroma-js" "^2.4.0" "@types/react-beautiful-dnd" "^13.1.3" From bdfabfc2f04a0ba47f6fe19cd6acca68983f1e4f Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 08:38:02 +0800 Subject: [PATCH 247/276] [Workspace]Essential/Analytics(All) use case overview page (#7673) (#7862) * navigates to use case overview page * Essential use case overviea page Changeset file for PR #7673 created/updated Revert "navigates to use case overview page" This reverts commit a43f533c4086cc742bd018ffa7a79a909e508897. * set breadcrumb for overview page * remove width * Analytics use case overview * add unit test * Changeset file for PR #7673 created/updated * add cardProps for card input * remove repeat license header * navigates to use case overvie page instead of workspace detail * Update src/plugins/content_management/public/components/card_container/card_embeddable.tsx * update page id to match pattern usecaseId_overview * fix import sample data target area * workspace icon * move all content ids to content management plugin * refactor whats_new and learn opensearch * fix merge issue * fix merge issue * unify use case page content id * add unit test --------- (cherry picked from commit 6931a41432ac03d885e19f3399d4a84fe9093e4c) Signed-off-by: Hailong Cui Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: SuZhou-Joe --- changelogs/fragments/7673.yml | 2 + src/core/public/index.ts | 4 + src/core/utils/default_nav_groups.ts | 17 +- src/core/utils/index.ts | 9 +- .../card_container/card_embeddable.test.tsx | 31 ++++ .../card_container/card_embeddable.tsx | 30 ++-- .../components/card_container/card_list.tsx | 7 +- .../public/components/card_container/types.ts | 2 + .../public/components/section_input.ts | 1 + .../public/components/section_render.tsx | 33 ++-- .../content_management/public/constants.ts | 55 +++++++ .../content_management/public/index.ts | 2 + .../content_management/public/mocks.ts | 1 + .../content_management_service.test.ts | 23 +++ .../content_management_service.ts | 23 +-- .../services/content_management/types.ts | 4 +- src/plugins/home/common/constants.ts | 12 -- .../public/application/components/home_app.js | 3 +- .../components/home_list_card.test.tsx | 64 +++++++- .../application/components/home_list_card.tsx | 68 ++++++++ .../sample_data/sample_data_card.test.tsx | 43 +++++ .../sample_data/sample_data_card.tsx | 45 +++++ .../home/public/application/home_render.tsx | 43 ++--- src/plugins/home/public/index.ts | 2 - src/plugins/home/public/plugin.ts | 8 + .../opensearch_dashboards.json | 2 +- .../saved_objects_management/public/plugin.ts | 12 +- src/plugins/workspace/common/constants.ts | 39 ----- .../workspace/opensearch_dashboards.json | 2 +- src/plugins/workspace/public/application.tsx | 18 ++ .../use_case_overview/get_started_cards.tsx | 73 +++++++++ .../components/use_case_overview/index.ts | 6 + .../use_case_overview/setup_overview.test.tsx | 150 +++++++++++++++++ .../use_case_overview/setup_overview.tsx | 154 ++++++++++++++++++ .../workspace_use_case_overview_app.tsx | 38 +++++ src/plugins/workspace/public/plugin.test.ts | 89 +++++++++- src/plugins/workspace/public/plugin.ts | 114 ++++++++++++- src/plugins/workspace/public/types.ts | 2 + src/plugins/workspace/public/utils.ts | 16 +- 39 files changed, 1109 insertions(+), 138 deletions(-) create mode 100644 changelogs/fragments/7673.yml create mode 100644 src/plugins/content_management/public/constants.ts create mode 100644 src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx create mode 100644 src/plugins/home/public/application/components/sample_data/sample_data_card.tsx create mode 100644 src/plugins/workspace/public/components/use_case_overview/get_started_cards.tsx create mode 100644 src/plugins/workspace/public/components/use_case_overview/index.ts create mode 100644 src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx create mode 100644 src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx create mode 100644 src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx diff --git a/changelogs/fragments/7673.yml b/changelogs/fragments/7673.yml new file mode 100644 index 000000000000..f0a84647bad2 --- /dev/null +++ b/changelogs/fragments/7673.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace]Essential/Analytics(All) use case overview page ([#7673](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7673)) \ No newline at end of file diff --git a/src/core/public/index.ts b/src/core/public/index.ts index a97f948a9d67..2398b16e7c03 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -112,6 +112,10 @@ export { cleanWorkspaceId, DEFAULT_NAV_GROUPS, ALL_USE_CASE_ID, + SEARCH_USE_CASE_ID, + ESSENTIAL_USE_CASE_ID, + OBSERVABILITY_USE_CASE_ID, + SECURITY_ANALYTICS_USE_CASE_ID, } from '../utils'; export { AppCategory, diff --git a/src/core/utils/default_nav_groups.ts b/src/core/utils/default_nav_groups.ts index 64fea126ff3e..7b3820ccfbd3 100644 --- a/src/core/utils/default_nav_groups.ts +++ b/src/core/utils/default_nav_groups.ts @@ -7,6 +7,10 @@ import { i18n } from '@osd/i18n'; import { ChromeNavGroup, NavGroupType } from '../types'; export const ALL_USE_CASE_ID = 'all'; +export const OBSERVABILITY_USE_CASE_ID = 'observability'; +export const SECURITY_ANALYTICS_USE_CASE_ID = 'security-analytics'; +export const ESSENTIAL_USE_CASE_ID = 'analytics'; +export const SEARCH_USE_CASE_ID = 'search'; const defaultNavGroups = { dataAdministration: { @@ -40,9 +44,10 @@ const defaultNavGroups = { defaultMessage: 'This is a use case contains all the features.', }), order: 3000, + icon: 'wsAnalytics', }, observability: { - id: 'observability', + id: OBSERVABILITY_USE_CASE_ID, title: i18n.translate('core.ui.group.observability.title', { defaultMessage: 'Observability', }), @@ -51,9 +56,10 @@ const defaultNavGroups = { 'Gain visibility into system health, performance, and reliability through monitoring and analysis of logs, metrics, and traces.', }), order: 4000, + icon: 'wsObservability', }, 'security-analytics': { - id: 'security-analytics', + id: SECURITY_ANALYTICS_USE_CASE_ID, title: i18n.translate('core.ui.group.security.analytics.title', { defaultMessage: 'Security Analytics', }), @@ -62,9 +68,10 @@ const defaultNavGroups = { 'Detect and investigate potential security threats and vulnerabilities across your systems and data.', }), order: 5000, + icon: 'wsSecurityAnalytics', }, essentials: { - id: 'analytics', + id: ESSENTIAL_USE_CASE_ID, title: i18n.translate('core.ui.group.essential.title', { defaultMessage: 'Essentials', }), @@ -73,9 +80,10 @@ const defaultNavGroups = { 'Analyze data to derive insights, identify patterns and trends, and make data-driven decisions.', }), order: 7000, + icon: 'wsEssentials', }, search: { - id: 'search', + id: SEARCH_USE_CASE_ID, title: i18n.translate('core.ui.group.search.title', { defaultMessage: 'Search', }), @@ -84,6 +92,7 @@ const defaultNavGroups = { "Quickly find and explore relevant information across your organization's data sources.", }), order: 6000, + icon: 'wsSearch', }, } as const; diff --git a/src/core/utils/index.ts b/src/core/utils/index.ts index 46304c4bde3d..3cb5f43d843c 100644 --- a/src/core/utils/index.ts +++ b/src/core/utils/index.ts @@ -39,4 +39,11 @@ export { export { DEFAULT_APP_CATEGORIES } from './default_app_categories'; export { WORKSPACE_PATH_PREFIX, WORKSPACE_TYPE } from './constants'; export { getWorkspaceIdFromUrl, formatUrlWithWorkspaceId, cleanWorkspaceId } from './workspace'; -export { DEFAULT_NAV_GROUPS, ALL_USE_CASE_ID } from './default_nav_groups'; +export { + DEFAULT_NAV_GROUPS, + ALL_USE_CASE_ID, + SEARCH_USE_CASE_ID, + ESSENTIAL_USE_CASE_ID, + OBSERVABILITY_USE_CASE_ID, + SECURITY_ANALYTICS_USE_CASE_ID, +} from './default_nav_groups'; diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx index a87cd43554ea..4a8c7a7a8f4c 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.test.tsx @@ -28,3 +28,34 @@ test('CardEmbeddable should render a card with the title', () => { Array.from(node.querySelectorAll('*')).find((ele) => ele.textContent?.trim() === 'card title') ).toBeFalsy(); }); + +test('CardEmbeddable should render a card with the cardProps', () => { + const embeddable = new CardEmbeddable({ + id: 'card-id', + title: 'card title', + description: '', + cardProps: { + selectable: { + children: 'selectable line', + onSelect: () => {}, + }, + }, + }); + + const node = document.createElement('div'); + embeddable.render(node); + + // it should render the card with title specified + expect( + Array.from(node.querySelectorAll('*')).find( + (ele) => ele.textContent?.trim() === 'selectable line' + ) + ).toBeTruthy(); + + embeddable.destroy(); + expect( + Array.from(node.querySelectorAll('*')).find( + (ele) => ele.textContent?.trim() === 'selectable line' + ) + ).toBeFalsy(); +}); diff --git a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx index 588ce1681957..1631b9e13959 100644 --- a/src/plugins/content_management/public/components/card_container/card_embeddable.tsx +++ b/src/plugins/content_management/public/components/card_container/card_embeddable.tsx @@ -5,7 +5,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { EuiCard } from '@elastic/eui'; +import { EuiCard, EuiCardProps } from '@elastic/eui'; import { Embeddable, EmbeddableInput, IContainer } from '../../../../embeddable/public'; @@ -15,6 +15,7 @@ export type CardEmbeddableInput = EmbeddableInput & { onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; + cardProps?: Omit; }; export class CardEmbeddable extends Embeddable { @@ -30,18 +31,21 @@ export class CardEmbeddable extends Embeddable { ReactDOM.unmountComponentAtNode(this.node); } this.node = node; - ReactDOM.render( - , - node - ); + + const cardProps: EuiCardProps = { + ...this.input.cardProps, + title: this.input.title ?? '', + description: this.input.description, + onClick: this.input.onClick, + icon: this.input?.getIcon?.(), + }; + + if (!cardProps.layout || cardProps.layout === 'vertical') { + cardProps.textAlign = 'left'; + cardProps.footer = this.input?.getFooter?.(); + } + + ReactDOM.render(, node); } public destroy() { diff --git a/src/plugins/content_management/public/components/card_container/card_list.tsx b/src/plugins/content_management/public/components/card_container/card_list.tsx index 37cf18adb048..2ab12a3ea084 100644 --- a/src/plugins/content_management/public/components/card_container/card_list.tsx +++ b/src/plugins/content_management/public/components/card_container/card_list.tsx @@ -47,7 +47,12 @@ const CardListInner = ({ embeddable, input, embeddableServices }: Props) => { const child = embeddable.getChild(panel.explicitInput.id); return ( - + ); }); diff --git a/src/plugins/content_management/public/components/card_container/types.ts b/src/plugins/content_management/public/components/card_container/types.ts index 8f4ea7855cab..4ddaf132ca93 100644 --- a/src/plugins/content_management/public/components/card_container/types.ts +++ b/src/plugins/content_management/public/components/card_container/types.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { EuiCardProps } from '@elastic/eui'; import { ContainerInput } from '../../../../embeddable/public'; export interface CardExplicitInput { @@ -11,6 +12,7 @@ export interface CardExplicitInput { onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; + cardProps?: Omit; } export type CardContainerInput = ContainerInput & { diff --git a/src/plugins/content_management/public/components/section_input.ts b/src/plugins/content_management/public/components/section_input.ts index 7d49f8a17ef9..3ae47b84881d 100644 --- a/src/plugins/content_management/public/components/section_input.ts +++ b/src/plugins/content_management/public/components/section_input.ts @@ -49,6 +49,7 @@ export const createCardInput = ( onClick: content.onClick, getIcon: content?.getIcon, getFooter: content?.getFooter, + cardProps: content.cardProps, }, }; } diff --git a/src/plugins/content_management/public/components/section_render.tsx b/src/plugins/content_management/public/components/section_render.tsx index d28fbad7296a..457b07cb7822 100644 --- a/src/plugins/content_management/public/components/section_render.tsx +++ b/src/plugins/content_management/public/components/section_render.tsx @@ -41,7 +41,12 @@ const DashboardSection = ({ section, embeddable, contents$, savedObjectsClient } if (section.kind === 'dashboard' && factory && input) { // const input = createDashboardSection(section, contents ?? []); - return ; + return ( + // to make dashboard section align with others add margin left and right -8px +
+ +
+ ); } return null; @@ -61,18 +66,20 @@ const CardSection = ({ section, embeddable, contents$ }: Props) => { if (section.kind === 'card' && factory && input) { return ( - - -

- - {section.title} -

-
+ + {section.title ? ( + +

+ + {section.title} +

+
+ ) : null} {isCardVisible && ( <> diff --git a/src/plugins/content_management/public/constants.ts b/src/plugins/content_management/public/constants.ts new file mode 100644 index 000000000000..e1d4ab07ecbc --- /dev/null +++ b/src/plugins/content_management/public/constants.ts @@ -0,0 +1,55 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + ESSENTIAL_USE_CASE_ID, + ALL_USE_CASE_ID, + SEARCH_USE_CASE_ID, + OBSERVABILITY_USE_CASE_ID, + SECURITY_ANALYTICS_USE_CASE_ID, +} from '../../../core/public'; + +// central place for all content ids rendered by content management + +// page ids +export const ANALYTICS_ALL_OVERVIEW_PAGE_ID = `${ALL_USE_CASE_ID}_overview`; +export const ESSENTIAL_OVERVIEW_PAGE_ID = `${ESSENTIAL_USE_CASE_ID}_overview`; +export const SEARCH_OVERVIEW_PAGE_ID = `${SEARCH_USE_CASE_ID}_overview`; +export const OBSERVABILITY_OVERVIEW_PAGE_ID = `${OBSERVABILITY_USE_CASE_ID}_overview`; +export const SECURITY_ANALYTICS_OVERVIEW_PAGE_ID = `${SECURITY_ANALYTICS_USE_CASE_ID}_overview`; +export const HOME_PAGE_ID = 'osd_homepage'; + +// section ids +export enum SECTIONS { + GET_STARTED = `get_started`, + SERVICE_CARDS = `service_cards`, + RECENTLY_VIEWED = `recently_viewed`, + DIFFERENT_SEARCH_TYPES = 'different_search_types', + CONFIG_EVALUATE_SEARCH = 'config_evaluate_search', +} + +export enum HOME_CONTENT_AREAS { + GET_STARTED = `${HOME_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${HOME_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} + +export enum ESSENTIAL_OVERVIEW_CONTENT_AREAS { + GET_STARTED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${ESSENTIAL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} + +export enum ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS { + GET_STARTED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, + SERVICE_CARDS = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, + RECENTLY_VIEWED = `${ANALYTICS_ALL_OVERVIEW_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, +} + +export enum SEARCH_OVERVIEW_CONTENT_AREAS { + DIFFERENT_SEARCH_TYPES = `${SEARCH_OVERVIEW_PAGE_ID}/${SECTIONS.DIFFERENT_SEARCH_TYPES}`, + CONFIG_EVALUATE_SEARCH = `${SEARCH_OVERVIEW_PAGE_ID}/${SECTIONS.CONFIG_EVALUATE_SEARCH}`, + GET_STARTED = `${SEARCH_OVERVIEW_PAGE_ID}/${SECTIONS.GET_STARTED}`, +} diff --git a/src/plugins/content_management/public/index.ts b/src/plugins/content_management/public/index.ts index c453782a7a9b..029e778d559b 100644 --- a/src/plugins/content_management/public/index.ts +++ b/src/plugins/content_management/public/index.ts @@ -13,3 +13,5 @@ export const plugin = (initializerContext: PluginInitializerContext) => export * from './components'; export * from './mocks'; +export * from './services/content_management'; +export * from './constants'; diff --git a/src/plugins/content_management/public/mocks.ts b/src/plugins/content_management/public/mocks.ts index 8f99be090231..79581c8e03dd 100644 --- a/src/plugins/content_management/public/mocks.ts +++ b/src/plugins/content_management/public/mocks.ts @@ -9,6 +9,7 @@ const createStartContract = (): ContentManagementPluginStart => { return { registerContentProvider: jest.fn(), renderPage: jest.fn(), + updatePageSection: jest.fn(), }; }; diff --git a/src/plugins/content_management/public/services/content_management/content_management_service.test.ts b/src/plugins/content_management/public/services/content_management/content_management_service.test.ts index b68157838b09..442b608513bb 100644 --- a/src/plugins/content_management/public/services/content_management/content_management_service.test.ts +++ b/src/plugins/content_management/public/services/content_management/content_management_service.test.ts @@ -47,6 +47,29 @@ test('it register content provider', () => { expect(cms.getPage('page1')?.getContents('section1')).toHaveLength(1); }); +test('it register content provider to multiple destination', () => { + const cms = new ContentManagementService(); + cms.registerPage({ id: 'page1', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); + cms.registerPage({ id: 'page2', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); + cms.registerContentProvider({ + id: 'content_provider1', + getTargetArea() { + return ['page1/section1', 'page2/section1']; + }, + getContent() { + return { + kind: 'card', + id: 'content1', + title: 'card', + description: 'descriptions', + order: 0, + }; + }, + }); + expect(cms.getPage('page1')?.getContents('section1')).toHaveLength(1); + expect(cms.getPage('page2')?.getContents('section1')).toHaveLength(1); +}); + test('it should throw error when register content provider with invalid target area', () => { const cms = new ContentManagementService(); cms.registerPage({ id: 'page1', sections: [{ id: 'section1', kind: 'card', order: 0 }] }); diff --git a/src/plugins/content_management/public/services/content_management/content_management_service.ts b/src/plugins/content_management/public/services/content_management/content_management_service.ts index 1c12ad826f56..c1a2f84a54d0 100644 --- a/src/plugins/content_management/public/services/content_management/content_management_service.ts +++ b/src/plugins/content_management/public/services/content_management/content_management_service.ts @@ -35,16 +35,19 @@ export class ContentManagementService { registerContentProvider = (provider: ContentProvider) => { this.contentProviders.set(provider.id, provider); - const targetArea = provider.getTargetArea(); - const [pageId, sectionId] = targetArea.split('/'); - - if (!pageId || !sectionId) { - throw new Error('getTargetArea() should return a string in format {pageId}/{sectionId}'); - } - - const page = this.getPage(pageId); - if (page) { - page.addContent(sectionId, provider.getContent()); + const area = provider.getTargetArea(); + const targetAreas: string[] = Array.isArray(area) ? [...area] : [area]; + for (const targetArea of targetAreas) { + const [pageId, sectionId] = targetArea.split('/'); + + if (!pageId || !sectionId) { + throw new Error('getTargetArea() should return a string in format {pageId}/{sectionId}'); + } + + const page = this.getPage(pageId); + if (page) { + page.addContent(sectionId, provider.getContent()); + } } }; diff --git a/src/plugins/content_management/public/services/content_management/types.ts b/src/plugins/content_management/public/services/content_management/types.ts index 755e6f426a0a..11253b1138e2 100644 --- a/src/plugins/content_management/public/services/content_management/types.ts +++ b/src/plugins/content_management/public/services/content_management/types.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { EuiCardProps } from '@elastic/eui'; import { CardContainerExplicitInput } from '../../components/card_container/types'; import { DashboardContainerExplicitInput } from '../../components/types'; @@ -74,6 +75,7 @@ export type Content = onClick?: () => void; getIcon?: () => React.ReactElement; getFooter?: () => React.ReactElement; + cardProps?: Omit; }; export type SavedObjectInput = @@ -95,5 +97,5 @@ export type SavedObjectInput = export interface ContentProvider { id: string; getContent: () => Content; - getTargetArea: () => string; + getTargetArea: () => string | string[]; } diff --git a/src/plugins/home/common/constants.ts b/src/plugins/home/common/constants.ts index 6d5c74267be0..25c78c59c4ac 100644 --- a/src/plugins/home/common/constants.ts +++ b/src/plugins/home/common/constants.ts @@ -32,15 +32,3 @@ export const PLUGIN_ID = 'home'; export const HOME_APP_BASE_PATH = `/app/${PLUGIN_ID}`; export const USE_NEW_HOME_PAGE = 'home:useNewHomePage'; export const IMPORT_SAMPLE_DATA_APP_ID = 'import_sample_data'; -export const HOME_PAGE_ID = 'osd_homepage'; -export enum SECTIONS { - GET_STARTED = `get_started`, - SERVICE_CARDS = `service_cards`, - RECENTLY_VIEWED = `recently_viewed`, -} - -export enum HOME_CONTENT_AREAS { - GET_STARTED = `${HOME_PAGE_ID}/${SECTIONS.GET_STARTED}`, - SERVICE_CARDS = `${HOME_PAGE_ID}/${SECTIONS.SERVICE_CARDS}`, - RECENTLY_VIEWED = `${HOME_PAGE_ID}/${SECTIONS.RECENTLY_VIEWED}`, -} diff --git a/src/plugins/home/public/application/components/home_app.js b/src/plugins/home/public/application/components/home_app.js index 4eb253a9cdd0..61596c724310 100644 --- a/src/plugins/home/public/application/components/home_app.js +++ b/src/plugins/home/public/application/components/home_app.js @@ -40,7 +40,8 @@ import { getTutorial } from '../load_tutorials'; import { replaceTemplateStrings } from './tutorial/replace_template_strings'; import { getServices } from '../opensearch_dashboards_services'; import { useMount } from 'react-use'; -import { USE_NEW_HOME_PAGE, HOME_PAGE_ID } from '../../../common/constants'; +import { USE_NEW_HOME_PAGE } from '../../../common/constants'; +import { HOME_PAGE_ID } from '../../../../content_management/public'; const RedirectToDefaultApp = () => { useMount(() => { diff --git a/src/plugins/home/public/application/components/home_list_card.test.tsx b/src/plugins/home/public/application/components/home_list_card.test.tsx index 8558c62727a4..f5916e4b74e7 100644 --- a/src/plugins/home/public/application/components/home_list_card.test.tsx +++ b/src/plugins/home/public/application/components/home_list_card.test.tsx @@ -6,7 +6,8 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { HomeListCard } from './home_list_card'; +import { HomeListCard, registerHomeListCardToPage } from './home_list_card'; +import { contentManagementPluginMocks } from '../../../../content_management/public'; describe('', () => { it('should render static content normally', async () => { @@ -60,3 +61,64 @@ it('should not show View All button when allLink is not provided', () => { const { queryByText } = render(); expect(queryByText('View all')).not.toBeInTheDocument(); }); + +describe('Register HomeListCardToPages', () => { + const registerContentProviderFn = jest.fn(); + const contentManagementStartMock = { + ...contentManagementPluginMocks.createStartContract(), + registerContentProvider: registerContentProviderFn, + }; + + it('register to use case overview page', () => { + registerHomeListCardToPage(contentManagementStartMock); + expect(contentManagementStartMock.registerContentProvider).toHaveBeenCalledTimes(4); + + let whatsNewCall = registerContentProviderFn.mock.calls[0]; + expect(whatsNewCall[0].getTargetArea()).toEqual('analytics_overview/service_cards'); + expect(whatsNewCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "whats_new", + "kind": "custom", + "order": 10, + "render": [Function], + "width": 24, + } + `); + + let learnOpenSearchCall = registerContentProviderFn.mock.calls[1]; + expect(learnOpenSearchCall[0].getTargetArea()).toEqual('analytics_overview/service_cards'); + expect(learnOpenSearchCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "learn_opensearch_new", + "kind": "custom", + "order": 20, + "render": [Function], + "width": 24, + } + `); + + whatsNewCall = registerContentProviderFn.mock.calls[2]; + expect(whatsNewCall[0].getTargetArea()).toEqual('all_overview/service_cards'); + expect(whatsNewCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "whats_new", + "kind": "custom", + "order": 30, + "render": [Function], + "width": undefined, + } + `); + + learnOpenSearchCall = registerContentProviderFn.mock.calls[3]; + expect(learnOpenSearchCall[0].getTargetArea()).toEqual('all_overview/service_cards'); + expect(learnOpenSearchCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "id": "learn_opensearch_new", + "kind": "custom", + "order": 40, + "render": [Function], + "width": undefined, + } + `); + }); +}); diff --git a/src/plugins/home/public/application/components/home_list_card.tsx b/src/plugins/home/public/application/components/home_list_card.tsx index e584635c680e..2d1cee86f838 100644 --- a/src/plugins/home/public/application/components/home_list_card.tsx +++ b/src/plugins/home/public/application/components/home_list_card.tsx @@ -17,6 +17,11 @@ import { EuiFlexItem, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; +import { + ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS, + ContentManagementPluginStart, + ESSENTIAL_OVERVIEW_CONTENT_AREAS, +} from '../../../../content_management/public'; export const LEARN_OPENSEARCH_CONFIG = { title: i18n.translate('homepage.card.learnOpenSearch.title', { @@ -116,3 +121,66 @@ export const HomeListCard = ({ config }: { config: Config }) => { ); }; + +export const registerHomeListCard = ( + contentManagement: ContentManagementPluginStart, + { + target, + order, + width, + config, + id, + }: { + target: string; + order: number; + width?: number; + config: Config; + id: string; + } +) => { + contentManagement.registerContentProvider({ + id: `${id}_${target}_cards`, + getContent: () => ({ + id, + kind: 'custom', + order, + width, + render: () => + React.createElement(HomeListCard, { + config, + }), + }), + getTargetArea: () => target, + }); +}; +export const registerHomeListCardToPage = (contentManagement: ContentManagementPluginStart) => { + registerHomeListCard(contentManagement, { + id: 'whats_new', + order: 10, + config: WHATS_NEW_CONFIG, + target: ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + width: 24, + }); + + registerHomeListCard(contentManagement, { + id: 'learn_opensearch_new', + order: 20, + config: LEARN_OPENSEARCH_CONFIG, + target: ESSENTIAL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + width: 24, + }); + + registerHomeListCard(contentManagement, { + id: 'whats_new', + order: 30, + config: WHATS_NEW_CONFIG, + target: ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + }); + + registerHomeListCard(contentManagement, { + id: 'learn_opensearch_new', + order: 40, + config: LEARN_OPENSEARCH_CONFIG, + target: ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.SERVICE_CARDS, + }); +}; diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx new file mode 100644 index 000000000000..44d7a4b6f007 --- /dev/null +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx @@ -0,0 +1,43 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { registerSampleDataCard } from './sample_data_card'; +import { coreMock } from '../../../../../../core/public/mocks'; +import { contentManagementPluginMocks } from '../../../../../content_management/public'; + +describe('Sample data card', () => { + const coreStart = coreMock.createStart(); + const registerContentProviderMock = jest.fn(); + + const contentManagement = { + ...contentManagementPluginMocks.createStartContract(), + registerContentProvider: registerContentProviderMock, + }; + + it('should call the getTargetArea function with the correct arguments', () => { + registerSampleDataCard(contentManagement, coreStart); + const call = registerContentProviderMock.mock.calls[0]; + expect(call[0].getTargetArea()).toEqual(['analytics_overview/get_started']); + expect(call[0].getContent()).toMatchInlineSnapshot(` + Object { + "cardProps": Object { + "selectable": Object { + "children": , + "isSelected": false, + "onClick": [Function], + }, + }, + "description": "You can install sample data to experiment with OpenSearch Dashboards.", + "id": "sample_data", + "kind": "card", + "order": 0, + "title": "Try openSearch", + } + `); + }); +}); diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx new file mode 100644 index 000000000000..4deb4eb8ff59 --- /dev/null +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.tsx @@ -0,0 +1,45 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreStart } from 'opensearch-dashboards/public'; +import React from 'react'; +import { EuiI18n } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { + ContentManagementPluginStart, + ESSENTIAL_OVERVIEW_CONTENT_AREAS, +} from '../../../../../content_management/public'; +import { IMPORT_SAMPLE_DATA_APP_ID } from '../../../../common/constants'; + +export const registerSampleDataCard = ( + contentManagement: ContentManagementPluginStart, + core: CoreStart +) => { + contentManagement.registerContentProvider({ + id: `get_start_sample_data`, + getTargetArea: () => [ESSENTIAL_OVERVIEW_CONTENT_AREAS.GET_STARTED], + getContent: () => ({ + id: 'sample_data', + kind: 'card', + order: 0, + description: i18n.translate('home.sampleData.card.description', { + defaultMessage: 'You can install sample data to experiment with OpenSearch Dashboards.', + }), + title: i18n.translate('home.sampleData.card.title', { + defaultMessage: 'Try openSearch', + }), + cardProps: { + selectable: { + children: , + isSelected: false, + onClick: () => { + // TODO change to a modal + core.application.navigateToApp(IMPORT_SAMPLE_DATA_APP_ID); + }, + }, + }, + }), + }); +}; diff --git a/src/plugins/home/public/application/home_render.tsx b/src/plugins/home/public/application/home_render.tsx index afddae56ce63..03babca342eb 100644 --- a/src/plugins/home/public/application/home_render.tsx +++ b/src/plugins/home/public/application/home_render.tsx @@ -8,12 +8,14 @@ import { CoreStart } from 'opensearch-dashboards/public'; import { ContentManagementPluginSetup, ContentManagementPluginStart, + HOME_PAGE_ID, + SECTIONS, + HOME_CONTENT_AREAS, } from '../../../../plugins/content_management/public'; -import { HOME_PAGE_ID, SECTIONS, HOME_CONTENT_AREAS } from '../../common/constants'; import { WHATS_NEW_CONFIG, LEARN_OPENSEARCH_CONFIG, - HomeListCard, + registerHomeListCard, } from './components/home_list_card'; export const setupHome = (contentManagement: ContentManagementPluginSetup) => { @@ -56,30 +58,19 @@ export const setupHome = (contentManagement: ContentManagementPluginSetup) => { }; export const initHome = (contentManagement: ContentManagementPluginStart, core: CoreStart) => { - contentManagement.registerContentProvider({ - id: 'whats_new_cards', - getContent: () => ({ - id: 'whats_new', - kind: 'custom', - order: 3, - render: () => - React.createElement(HomeListCard, { - config: WHATS_NEW_CONFIG, - }), - }), - getTargetArea: () => HOME_CONTENT_AREAS.SERVICE_CARDS, + registerHomeListCard(contentManagement, { + id: 'whats_new', + order: 3, + config: WHATS_NEW_CONFIG, + target: HOME_CONTENT_AREAS.SERVICE_CARDS, + width: 16, }); - contentManagement.registerContentProvider({ - id: 'learn_opensearch_new_cards', - getContent: () => ({ - id: 'learn_opensearch', - kind: 'custom', - order: 4, - render: () => - React.createElement(HomeListCard, { - config: LEARN_OPENSEARCH_CONFIG, - }), - }), - getTargetArea: () => HOME_CONTENT_AREAS.SERVICE_CARDS, + + registerHomeListCard(contentManagement, { + id: 'learn_opensearch_new', + order: 4, + config: LEARN_OPENSEARCH_CONFIG, + target: HOME_CONTENT_AREAS.SERVICE_CARDS, + width: 16, }); }; diff --git a/src/plugins/home/public/index.ts b/src/plugins/home/public/index.ts index d252a31a0977..58ad10cdf04b 100644 --- a/src/plugins/home/public/index.ts +++ b/src/plugins/home/public/index.ts @@ -53,5 +53,3 @@ import { HomePublicPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => new HomePublicPlugin(initializerContext); - -export { HOME_PAGE_ID, HOME_CONTENT_AREAS } from '../common/constants'; diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index cf499c19ddb9..8e32537d0a0b 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -71,6 +71,8 @@ import { ContentManagementPluginStart, } from '../../content_management/public'; import { initHome, setupHome } from './application/home_render'; +import { registerSampleDataCard } from './application/components/sample_data/sample_data_card'; +import { registerHomeListCardToPage } from './application/components/home_list_card'; import { toMountPoint } from '../../opensearch_dashboards_react/public'; import { HomeIcon } from './application/components/home_icon'; @@ -231,6 +233,12 @@ export class HomePublicPlugin // initialize homepage initHome(contentManagement, core); + // register sample data card to use case overview page + registerSampleDataCard(contentManagement, core); + + // register what's new learn opensearch card to use case overview page + registerHomeListCardToPage(contentManagement); + this.featuresCatalogueRegistry.start({ capabilities }); this.sectionTypeService.start({ core, data }); diff --git a/src/plugins/saved_objects_management/opensearch_dashboards.json b/src/plugins/saved_objects_management/opensearch_dashboards.json index 9a985345b030..5b6236ad2630 100644 --- a/src/plugins/saved_objects_management/opensearch_dashboards.json +++ b/src/plugins/saved_objects_management/opensearch_dashboards.json @@ -16,5 +16,5 @@ "contentManagement" ], "extraPublicDirs": ["public/lib"], - "requiredBundles": ["opensearchDashboardsReact", "home"] + "requiredBundles": ["opensearchDashboardsReact", "home", "contentManagement"] } diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index 104507f028e2..5a0a4cfe0330 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -65,7 +65,11 @@ import { registerServices } from './register_services'; import { bootstrap } from './ui_actions_bootstrap'; import { DEFAULT_NAV_GROUPS } from '../../../core/public'; import { RecentWork } from './management_section/recent_work'; -import { HOME_CONTENT_AREAS } from '../../../plugins/home/public'; +import { + HOME_CONTENT_AREAS, + ESSENTIAL_OVERVIEW_CONTENT_AREAS, + ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS, +} from '../../../plugins/content_management/public'; import { getScopedBreadcrumbs } from '../../opensearch_dashboards_react/public'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; @@ -236,7 +240,11 @@ export class SavedObjectsManagementPlugin }), }; }, - getTargetArea: () => HOME_CONTENT_AREAS.RECENTLY_VIEWED, + getTargetArea: () => [ + HOME_CONTENT_AREAS.RECENTLY_VIEWED, + ESSENTIAL_OVERVIEW_CONTENT_AREAS.RECENTLY_VIEWED, + ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.RECENTLY_VIEWED, + ], }); return { diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index 7cabf32d14c6..735c253fd0c0 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -4,7 +4,6 @@ */ import { i18n } from '@osd/i18n'; -import { AppCategory } from '../../../core/types'; export const WORKSPACE_FATAL_ERROR_APP_ID = 'workspace_fatal_error'; export const WORKSPACE_CREATE_APP_ID = 'workspace_create'; @@ -38,44 +37,6 @@ export const PRIORITY_FOR_WORKSPACE_UI_SETTINGS_WRAPPER = -2; export const PRIORITY_FOR_WORKSPACE_CONFLICT_CONTROL_WRAPPER = -1; export const PRIORITY_FOR_PERMISSION_CONTROL_WRAPPER = 0; -export const WORKSPACE_APP_CATEGORIES: Record = Object.freeze({ - // below categories are for workspace - getStarted: { - id: 'getStarted', - label: i18n.translate('core.ui.getStarted.label', { - defaultMessage: 'Get started', - }), - order: 10000, - }, - dashboardAndReport: { - id: 'dashboardReport', - label: i18n.translate('core.ui.dashboardReport.label', { - defaultMessage: 'Dashboard and report', - }), - order: 11000, - }, - investigate: { - id: 'investigate', - label: i18n.translate('core.ui.investigate.label', { - defaultMessage: 'Investigate', - }), - order: 12000, - }, - detect: { - id: 'detect', - label: i18n.translate('core.ui.detect.label', { - defaultMessage: 'Detect', - }), - order: 13000, - }, - searchSolution: { - id: 'searchSolution', - label: i18n.translate('core.ui.searchSolution.label', { - defaultMessage: 'Build search solution', - }), - order: 14000, - }, -}); /** * * This is a temp solution to store relationships between use cases and features. diff --git a/src/plugins/workspace/opensearch_dashboards.json b/src/plugins/workspace/opensearch_dashboards.json index ac24c20d712b..9818ab60966d 100644 --- a/src/plugins/workspace/opensearch_dashboards.json +++ b/src/plugins/workspace/opensearch_dashboards.json @@ -9,5 +9,5 @@ "navigation" ], "optionalPlugins": ["savedObjectsManagement","management","dataSourceManagement","contentManagement"], - "requiredBundles": ["opensearchDashboardsReact", "home","dataSource"] + "requiredBundles": ["opensearchDashboardsReact","dataSource","contentManagement"] } diff --git a/src/plugins/workspace/public/application.tsx b/src/plugins/workspace/public/application.tsx index cbc45c938586..88a7825b6883 100644 --- a/src/plugins/workspace/public/application.tsx +++ b/src/plugins/workspace/public/application.tsx @@ -16,6 +16,7 @@ import { WorkspaceCreatorProps } from './components/workspace_creator/workspace_ import { WorkspaceDetailApp } from './components/workspace_detail_app'; import { WorkspaceDetailProps } from './components/workspace_detail/workspace_detail'; import { WorkspaceInitialApp } from './components/workspace_initial_app'; +import { WorkspaceUseCaseOverviewApp } from './components/workspace_use_case_overview_app'; export const renderCreatorApp = ( { element }: AppMountParameters, @@ -102,3 +103,20 @@ export const renderInitialApp = ({}: AppMountParameters, services: Services) => ReactDOM.unmountComponentAtNode(rootElement!); }; }; + +export const renderUseCaseOverviewApp = async ( + { element }: AppMountParameters, + services: Services, + pageId: string +) => { + ReactDOM.render( + + + , + element + ); + + return () => { + ReactDOM.unmountComponentAtNode(element); + }; +}; diff --git a/src/plugins/workspace/public/components/use_case_overview/get_started_cards.tsx b/src/plugins/workspace/public/components/use_case_overview/get_started_cards.tsx new file mode 100644 index 000000000000..f4edb5466215 --- /dev/null +++ b/src/plugins/workspace/public/components/use_case_overview/get_started_cards.tsx @@ -0,0 +1,73 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiI18n } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import React from 'react'; + +interface GetStartCard { + id: string; + title: string; + description: string; + footer: React.JSX.Element; + navigateAppId: string; + order: number; +} + +const DISCOVER_APP_ID = 'discover'; +const VISUALIZE_APP_ID = 'visualize'; +const DASHBOARDS_APP_ID = 'dashboards'; + +export const getStartedCards: GetStartCard[] = [ + { + id: 'get_start_discover', + title: i18n.translate('workspace.essential_overview.discover.card.title', { + defaultMessage: 'Discover insights', + }), + description: i18n.translate('workspace.essential_overview.discover.card.description', { + defaultMessage: 'Explore data interactively to uncover insights.', + }), + footer: ( + + ), + navigateAppId: DISCOVER_APP_ID, + order: 20, + }, + { + id: 'get_start_visualization', + title: i18n.translate('workspace.essential_overview.visualize.card.title', { + defaultMessage: 'Visualize data', + }), + description: i18n.translate('workspace.essential_overview.visualize.card.description', { + defaultMessage: + 'Unlock insightful data exploration with visualization and aggregation tools.', + }), + footer: ( + + ), + navigateAppId: VISUALIZE_APP_ID, + order: 30, + }, + { + id: 'get_start_dashboards', + title: i18n.translate('workspace.essential_overview.dashboards.card.title', { + defaultMessage: 'View the big picture', + }), + description: i18n.translate('workspace.essential_overview.dashboards.card.description', { + defaultMessage: 'Gain clarity and visibility with dynamic data visualization tools.', + }), + footer: ( + + ), + navigateAppId: DASHBOARDS_APP_ID, + order: 40, + }, +]; diff --git a/src/plugins/workspace/public/components/use_case_overview/index.ts b/src/plugins/workspace/public/components/use_case_overview/index.ts new file mode 100644 index 000000000000..9691737d216d --- /dev/null +++ b/src/plugins/workspace/public/components/use_case_overview/index.ts @@ -0,0 +1,6 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { setEssentialOverviewSection, registerEssentialOverviewContent } from './setup_overview'; diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx new file mode 100644 index 000000000000..0d8733a21ce7 --- /dev/null +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.test.tsx @@ -0,0 +1,150 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + ContentManagementPluginSetup, + ContentManagementPluginStart, +} from '../../../../../plugins/content_management/public'; +import { coreMock } from '../../../../../core/public/mocks'; +import { + registerAnalyticsAllOverviewContent, + registerEssentialOverviewContent, + setEssentialOverviewSection, +} from './setup_overview'; + +describe('Setup use case overview', () => { + const coreStart = coreMock.createStart(); + const registerContentProviderMock = jest.fn(); + + const contentManagementStartMock: ContentManagementPluginStart = { + registerContentProvider: registerContentProviderMock, + renderPage: jest.fn(), + updatePageSection: jest.fn(), + }; + + const registerPageMock = jest.fn(); + const contentManagementSetupMock: ContentManagementPluginSetup = { + registerPage: registerPageMock, + }; + + beforeEach(() => { + registerContentProviderMock.mockClear(); + }); + + it('setEssentialOverviewSection', () => { + setEssentialOverviewSection(contentManagementSetupMock); + + const call = registerPageMock.mock.calls[0]; + expect(call[0]).toMatchInlineSnapshot(` + Object { + "id": "analytics_overview", + "sections": Array [ + Object { + "id": "service_cards", + "kind": "dashboard", + "order": 3000, + }, + Object { + "id": "recently_viewed", + "kind": "custom", + "order": 2000, + "render": [Function], + "title": "Recently viewed", + }, + Object { + "id": "get_started", + "kind": "card", + "order": 1000, + }, + ], + "title": "Overview", + } + `); + }); + + it('registerEssentialOverviewContent', () => { + registerEssentialOverviewContent(contentManagementStartMock, coreStart); + + const calls = registerContentProviderMock.mock.calls; + expect(calls.length).toBe(3); + + const firstCall = calls[0]; + expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"analytics_overview/get_started"`); + expect(firstCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "cardProps": Object { + "selectable": Object { + "children": , + "isSelected": false, + "onClick": [Function], + }, + }, + "description": "Explore data interactively to uncover insights.", + "id": "get_start_discover", + "kind": "card", + "order": 20, + "title": "Discover insights", + } + `); + }); + + it('setAnalyticsAllOverviewSection', () => { + setEssentialOverviewSection(contentManagementSetupMock); + + const call = registerPageMock.mock.calls[0]; + expect(call[0]).toMatchInlineSnapshot(` + Object { + "id": "analytics_overview", + "sections": Array [ + Object { + "id": "service_cards", + "kind": "dashboard", + "order": 3000, + }, + Object { + "id": "recently_viewed", + "kind": "custom", + "order": 2000, + "render": [Function], + "title": "Recently viewed", + }, + Object { + "id": "get_started", + "kind": "card", + "order": 1000, + }, + ], + "title": "Overview", + } + `); + }); + + it('registerAnalyticsAllOverviewContent', () => { + registerAnalyticsAllOverviewContent(contentManagementStartMock, coreStart); + + const calls = registerContentProviderMock.mock.calls; + expect(calls.length).toBe(3); + + const firstCall = calls[0]; + expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"all_overview/get_started"`); + expect(firstCall[0].getContent()).toMatchInlineSnapshot(` + Object { + "cardProps": Object { + "layout": "horizontal", + }, + "description": "Gain visibility into system health, performance, and reliability through monitoring and analysis of logs, metrics, and traces.", + "getIcon": [Function], + "id": "observability", + "kind": "card", + "onClick": [Function], + "order": 4000, + "title": "Observability", + } + `); + }); +}); diff --git a/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx new file mode 100644 index 000000000000..4b801bf0880d --- /dev/null +++ b/src/plugins/workspace/public/components/use_case_overview/setup_overview.tsx @@ -0,0 +1,154 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { EuiIcon } from '@elastic/eui'; +import { first } from 'rxjs/operators'; +import { + ContentManagementPluginSetup, + ContentManagementPluginStart, + ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS, + ANALYTICS_ALL_OVERVIEW_PAGE_ID, + ESSENTIAL_OVERVIEW_CONTENT_AREAS, + ESSENTIAL_OVERVIEW_PAGE_ID, + SECTIONS, +} from '../../../../content_management/public'; +import { getStartedCards } from './get_started_cards'; +import { DEFAULT_NAV_GROUPS } from '../../../../../core/public'; +import { Content } from '../../../../../plugins/content_management/public'; + +const recentlyViewSectionRender = (contents: Content[]) => { + return ( + <> + {contents.map((content) => { + if (content.kind === 'custom') { + return content.render(); + } + + return null; + })} + + ); +}; + +// Essential overview part +export const setEssentialOverviewSection = (contentManagement: ContentManagementPluginSetup) => { + contentManagement.registerPage({ + id: ESSENTIAL_OVERVIEW_PAGE_ID, + title: 'Overview', + sections: [ + { + id: SECTIONS.SERVICE_CARDS, + order: 3000, + kind: 'dashboard', + }, + { + id: SECTIONS.RECENTLY_VIEWED, + order: 2000, + title: 'Recently viewed', + kind: 'custom', + render: recentlyViewSectionRender, + }, + { + id: SECTIONS.GET_STARTED, + order: 1000, + kind: 'card', + }, + ], + }); +}; + +export const registerEssentialOverviewContent = ( + contentManagement: ContentManagementPluginStart, + core: CoreStart +) => { + getStartedCards.forEach((card) => { + contentManagement.registerContentProvider({ + id: card.id, + getTargetArea: () => ESSENTIAL_OVERVIEW_CONTENT_AREAS.GET_STARTED, + getContent: () => ({ + id: card.id, + kind: 'card', + order: card.order, + description: card.description, + title: card.title, + cardProps: { + selectable: { + onClick: () => { + core.application.navigateToApp(card.navigateAppId); + }, + children: card.footer, + isSelected: false, + }, + }, + }), + }); + }); +}; + +// Analytics(All) overview part +export const setAnalyticsAllOverviewSection = (contentManagement: ContentManagementPluginSetup) => { + contentManagement.registerPage({ + id: ANALYTICS_ALL_OVERVIEW_PAGE_ID, + title: 'Overview', + sections: [ + { + id: SECTIONS.SERVICE_CARDS, + order: 3000, + kind: 'dashboard', + }, + { + id: SECTIONS.RECENTLY_VIEWED, + order: 2000, + title: 'Recently viewed', + kind: 'custom', + render: recentlyViewSectionRender, + }, + { + id: SECTIONS.GET_STARTED, + order: 1000, + kind: 'card', + }, + ], + }); +}; + +export const registerAnalyticsAllOverviewContent = ( + contentManagement: ContentManagementPluginStart, + core: CoreStart +) => { + const useCaseCards = [ + DEFAULT_NAV_GROUPS.observability, + DEFAULT_NAV_GROUPS['security-analytics'], + DEFAULT_NAV_GROUPS.search, + ]; + useCaseCards.forEach((card, index) => { + contentManagement.registerContentProvider({ + id: card.id, + getTargetArea: () => ANALYTICS_ALL_OVERVIEW_CONTENT_AREAS.GET_STARTED, + getContent: () => ({ + id: card.id, + kind: 'card', + getIcon: () => + React.createElement(EuiIcon, { size: 'xl', type: card.icon || 'wsSelector' }), + order: card.order || index, + description: card.description, + title: card.title, + cardProps: { + layout: 'horizontal', + }, + onClick: async () => { + const navGroups = await core.chrome.navGroup.getNavGroupsMap$().pipe(first()).toPromise(); + const group = navGroups[card.id]; + if (group) { + const appId = group.navLinks?.[0].id; + if (appId) core.application.navigateToApp(appId); + } + }, + }), + }); + }); +}; diff --git a/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx b/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx new file mode 100644 index 000000000000..dcdcee22b729 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_use_case_overview_app.tsx @@ -0,0 +1,38 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect } from 'react'; +import { I18nProvider } from '@osd/i18n/react'; +import { useObservable } from 'react-use'; +import { EuiBreadcrumb } from '@elastic/eui'; +import { useOpenSearchDashboards } from '../../../opensearch_dashboards_react/public'; +import { Services } from '../types'; + +interface WorkspaceUseCaseOverviewProps { + pageId: string; +} + +export const WorkspaceUseCaseOverviewApp = (props: WorkspaceUseCaseOverviewProps) => { + const { + services: { contentManagement, workspaces, chrome }, + } = useOpenSearchDashboards(); + + const currentWorkspace = useObservable(workspaces.currentWorkspace$); + + useEffect(() => { + const breadcrumbs: EuiBreadcrumb[] = [ + { + text: currentWorkspace?.name, + }, + ]; + chrome.setBreadcrumbs(breadcrumbs); + }, [chrome, currentWorkspace]); + + const pageId = props.pageId; + + return ( + {contentManagement ? contentManagement.renderPage(pageId) : null} + ); +}; diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 4eaa8d54903b..3be162a4522e 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -180,7 +180,7 @@ describe('Workspace plugin', () => { ); }); - it('#setup should register workspace detail', async () => { + it('#setup should register workspace detail with a hidden application and not register to all nav group', async () => { const setupMock = coreMock.createSetup(); setupMock.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); const workspacePlugin = new WorkspacePlugin(); @@ -191,6 +191,18 @@ describe('Workspace plugin', () => { id: 'workspace_detail', }) ); + + // not register to all nav group + expect(setupMock.chrome.navGroup.addNavLinksToGroup).not.toHaveBeenCalledWith( + DEFAULT_NAV_GROUPS.all, + expect.arrayContaining([ + { + id: 'workspace_detail', + title: 'Overview', + order: 100, + }, + ]) + ); }); it('#setup should register workspace initial with a visible application', async () => { @@ -206,11 +218,84 @@ describe('Workspace plugin', () => { ); }); + it('#setup should register workspace essential use case when new home is disabled', async () => { + const setupMock = { + ...coreMock.createSetup(), + chrome: { + ...coreMock.createSetup().chrome, + navGroup: { + ...coreMock.createSetup().chrome.navGroup, + getNavGroupEnabled: jest.fn().mockReturnValue(false), + }, + }, + }; + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, { + contentManagement: { + registerPage: jest.fn(), + }, + }); + + expect(setupMock.application.register).not.toHaveBeenCalledWith( + expect.objectContaining({ + id: 'essential_overview', + }) + ); + expect(setupMock.application.register).not.toHaveBeenCalledWith( + expect.objectContaining({ + id: 'analytics_all_overview', + }) + ); + }); + + it('#setup should register workspace essential use case when new nav is enabled', async () => { + const setupMock = { + ...coreMock.createSetup(), + chrome: { + ...coreMock.createSetup().chrome, + navGroup: { + ...coreMock.createSetup().chrome.navGroup, + getNavGroupEnabled: jest.fn().mockReturnValue(true), + }, + }, + }; + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, { + contentManagement: { + registerPage: jest.fn(), + }, + }); + + expect(setupMock.application.register).toHaveBeenCalledWith( + expect.objectContaining({ + id: 'analytics_overview', + }) + ); + }); + + it('#setup should register workspace analytics(All) use case when new nav is enabled', async () => { + const setupMock = { + ...coreMock.createSetup(), + chrome: { + ...coreMock.createSetup().chrome, + navGroup: { + ...coreMock.createSetup().chrome.navGroup, + getNavGroupEnabled: jest.fn().mockReturnValue(true), + }, + }, + }; + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, { + contentManagement: { + registerPage: jest.fn(), + }, + }); + }); + it('#setup should register workspace navigation with a visible application', async () => { const setupMock = coreMock.createSetup(); const workspacePlugin = new WorkspacePlugin(); await workspacePlugin.setup(setupMock, {}); - expect(setupMock.application.register).toHaveBeenCalledWith( expect.objectContaining({ id: 'workspace_navigation', diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 1617744fa9ff..03c6b544b64d 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -38,7 +38,12 @@ import { Services, WorkspaceUseCase } from './types'; import { WorkspaceClient } from './workspace_client'; import { SavedObjectsManagementPluginSetup } from '../../../plugins/saved_objects_management/public'; import { ManagementSetup } from '../../../plugins/management/public'; -import { ContentManagementPluginStart } from '../../../plugins/content_management/public'; +import { + ANALYTICS_ALL_OVERVIEW_PAGE_ID, + ContentManagementPluginSetup, + ContentManagementPluginStart, + ESSENTIAL_OVERVIEW_PAGE_ID, +} from '../../../plugins/content_management/public'; import { WorkspaceMenu } from './components/workspace_menu/workspace_menu'; import { getWorkspaceColumn } from './components/workspace_column'; import { DataSourceManagementPluginSetup } from '../../../plugins/data_source_management/public'; @@ -55,8 +60,16 @@ import { toMountPoint } from '../../opensearch_dashboards_react/public'; import { UseCaseService } from './services/use_case_service'; import { WorkspaceListCard } from './components/service_card'; import { UseCaseFooter } from './components/home_get_start_card'; -import { HOME_CONTENT_AREAS } from '../../home/public'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; +import { HOME_CONTENT_AREAS } from '../../../plugins/content_management/public'; +import { + registerEssentialOverviewContent, + setEssentialOverviewSection, +} from './components/use_case_overview'; +import { + registerAnalyticsAllOverviewContent, + setAnalyticsAllOverviewSection, +} from './components/use_case_overview/setup_overview'; type WorkspaceAppType = ( params: AppMountParameters, @@ -68,6 +81,7 @@ interface WorkspacePluginSetupDeps { savedObjectsManagement?: SavedObjectsManagementPluginSetup; management?: ManagementSetup; dataSourceManagement?: DataSourceManagementPluginSetup; + contentManagement?: ContentManagementPluginSetup; } export interface WorkspacePluginStartDeps { @@ -113,7 +127,16 @@ export class WorkspacePlugin this.registeredUseCases$, ]).subscribe(([currentWorkspace, registeredUseCases]) => { if (currentWorkspace) { + const workspaceUseCase = currentWorkspace.features + ? getFirstUseCaseOfFeatureConfigs(currentWorkspace.features) + : undefined; + this.appUpdater$.next((app) => { + // essential use overview is only available in essential workspace + if (app.id === ESSENTIAL_OVERVIEW_PAGE_ID && workspaceUseCase === ALL_USE_CASE_ID) { + return { status: AppStatus.inaccessible }; + } + if (isAppAccessibleInWorkspace(app, currentWorkspace, registeredUseCases)) { return; } @@ -230,7 +253,12 @@ export class WorkspacePlugin public async setup( core: CoreSetup, - { savedObjectsManagement, management, dataSourceManagement }: WorkspacePluginSetupDeps + { + savedObjectsManagement, + management, + dataSourceManagement, + contentManagement, + }: WorkspacePluginSetupDeps ) { const workspaceClient = new WorkspaceClient(core.http, core.workspaces); await workspaceClient.init(); @@ -412,6 +440,78 @@ export class WorkspacePlugin workspaceAvailability: WorkspaceAvailability.outsideWorkspace, }); + if (core.chrome.navGroup.getNavGroupEnabled() && contentManagement) { + // workspace essential use case overview + core.application.register({ + id: ESSENTIAL_OVERVIEW_PAGE_ID, + title: '', + async mount(params: AppMountParameters) { + const { renderUseCaseOverviewApp } = await import('./application'); + const [ + coreStart, + { contentManagement: contentManagementStart }, + ] = await core.getStartServices(); + const services = { + ...coreStart, + workspaceClient, + dataSourceManagement, + contentManagement: contentManagementStart, + }; + + return renderUseCaseOverviewApp(params, services, ESSENTIAL_OVERVIEW_PAGE_ID); + }, + workspaceAvailability: WorkspaceAvailability.insideWorkspace, + }); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.essentials, [ + { + id: ESSENTIAL_OVERVIEW_PAGE_ID, + order: -1, + title: i18n.translate('workspace.nav.essential_overview.title', { + defaultMessage: 'Overview', + }), + }, + ]); + + // initial the page structure + setEssentialOverviewSection(contentManagement); + + // register workspace Analytics(all) use case overview app + core.application.register({ + id: ANALYTICS_ALL_OVERVIEW_PAGE_ID, + title: '', + async mount(params: AppMountParameters) { + const { renderUseCaseOverviewApp } = await import('./application'); + const [ + coreStart, + { contentManagement: contentManagementStart }, + ] = await core.getStartServices(); + const services = { + ...coreStart, + workspaceClient, + dataSourceManagement, + contentManagement: contentManagementStart, + }; + + return renderUseCaseOverviewApp(params, services, ANALYTICS_ALL_OVERVIEW_PAGE_ID); + }, + workspaceAvailability: WorkspaceAvailability.insideWorkspace, + }); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ + { + id: ANALYTICS_ALL_OVERVIEW_PAGE_ID, + order: -1, + title: i18n.translate('workspace.nav.analyticsAll_overview.title', { + defaultMessage: 'Overview', + }), + }, + ]); + + // initial the page structure + setAnalyticsAllOverviewSection(contentManagement); + } + /** * register workspace column into saved objects table */ @@ -447,7 +547,7 @@ export class WorkspacePlugin useCases.forEach((useCase, index) => { contentManagement.registerContentProvider({ id: `home_get_start_${useCase.id}`, - getTargetArea: () => HOME_CONTENT_AREAS.GET_STARTED, + getTargetArea: () => [HOME_CONTENT_AREAS.GET_STARTED], getContent: () => ({ id: useCase.id, kind: 'card', @@ -509,6 +609,12 @@ export class WorkspacePlugin // set breadcrumbs enricher for workspace this.breadcrumbsSubscription = enrichBreadcrumbsWithWorkspace(core); + + // register content to essential overview page + registerEssentialOverviewContent(contentManagement, core); + + // register content to analytics(All) overview page + registerAnalyticsAllOverviewContent(contentManagement, core); } return {}; } diff --git a/src/plugins/workspace/public/types.ts b/src/plugins/workspace/public/types.ts index 6d47262bbdd9..bec84221e2f1 100644 --- a/src/plugins/workspace/public/types.ts +++ b/src/plugins/workspace/public/types.ts @@ -7,12 +7,14 @@ import { CoreStart } from '../../../core/public'; import { WorkspaceClient } from './workspace_client'; import { DataSourceManagementPluginSetup } from '../../../plugins/data_source_management/public'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; +import { ContentManagementPluginStart } from '../../../plugins/content_management/public'; import { DataSourceAttributes } from '../../../plugins/data_source/common/data_sources'; export type Services = CoreStart & { workspaceClient: WorkspaceClient; dataSourceManagement?: DataSourceManagementPluginSetup; navigationUI?: NavigationPublicPluginStart['ui']; + contentManagement?: ContentManagementPluginStart; }; export interface WorkspaceUseCaseFeature { diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index 543a79fbc4a3..01969d15159c 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -13,6 +13,7 @@ import { ChromeBreadcrumb, ApplicationStart, HttpSetup, + DEFAULT_NAV_GROUPS, } from '../../../core/public'; import { App, @@ -27,6 +28,10 @@ import { WORKSPACE_DETAIL_APP_ID } from '../common/constants'; import { WorkspaceUseCase, WorkspaceUseCaseFeature } from './types'; import { formatUrlWithWorkspaceId } from '../../../core/public/utils'; import { SigV4ServiceName } from '../../../plugins/data_source/common/data_sources'; +import { + ANALYTICS_ALL_OVERVIEW_PAGE_ID, + ESSENTIAL_OVERVIEW_PAGE_ID, +} from '../../../plugins/content_management/public'; export const USE_CASE_PREFIX = 'use-case-'; @@ -325,7 +330,11 @@ export function prependWorkspaceToBreadcrumbs( currentNavGroup: NavGroupItemInMap | undefined, navGroupsMap: Record ) { - if (appId === WORKSPACE_DETAIL_APP_ID) { + if ( + appId === WORKSPACE_DETAIL_APP_ID || + appId === ESSENTIAL_OVERVIEW_PAGE_ID || + appId === ANALYTICS_ALL_OVERVIEW_PAGE_ID + ) { core.chrome.setBreadcrumbsEnricher(undefined); return; } @@ -371,7 +380,7 @@ export function prependWorkspaceToBreadcrumbs( }, }; if (useCase === ALL_USE_CASE_ID) { - if (currentNavGroup) { + if (currentNavGroup && currentNavGroup.id !== DEFAULT_NAV_GROUPS.all.id) { return [homeBreadcrumb, workspaceBreadcrumb, navGroupBreadcrumb, ...breadcrumbs]; } else { return [homeBreadcrumb, workspaceBreadcrumb, ...breadcrumbs]; @@ -389,8 +398,7 @@ export const getUseCaseUrl = ( application: ApplicationStart, http: HttpSetup ): string => { - const appId = - (useCase?.id !== ALL_USE_CASE_ID && useCase?.features?.[0].id) || WORKSPACE_DETAIL_APP_ID; + const appId = useCase?.features?.[0].id || WORKSPACE_DETAIL_APP_ID; const useCaseURL = formatUrlWithWorkspaceId( application.getUrlForApp(appId, { absolute: false, From 23fbaf13107ac85082d33d55d4a86c8accd63a96 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:13:27 +0800 Subject: [PATCH 248/276] use compress EuiDescriptionList (#7861) (#7876) (cherry picked from commit 930e24432a675e8fb945c2792e58928f4b513180) Signed-off-by: Hailong Cui Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../public/components/service_card/workspace_list_card.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx b/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx index e143d5d9f9fb..1f3086494888 100644 --- a/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx +++ b/src/plugins/workspace/public/components/service_card/workspace_list_card.tsx @@ -101,7 +101,7 @@ export const WorkspaceListCard = (props: WorkspaceListCardProps) => { const createWorkspaceButton = ( { /> ) : ( Date: Wed, 28 Aug 2024 15:09:08 +0800 Subject: [PATCH 249/276] Use small button, small padding and compressed. (#7878) Signed-off-by: yubonluo --- changelogs/fragments/7842.yml | 2 ++ .../home_get_start_card/use_case_footer.tsx | 27 ++++++++++--------- .../workspace_detail.test.tsx.snap | 10 +++---- .../association_data_source_modal.tsx | 10 +++---- .../opensearch_connections_table.tsx | 6 ++--- .../workspace_detail_form_details.tsx | 8 +++--- .../workspace_initial.test.tsx.snap | 12 ++++----- .../workspace_initial/workspace_initial.tsx | 10 +++---- .../workspace_menu/workspace_menu.tsx | 16 +++++------ 9 files changed, 51 insertions(+), 50 deletions(-) create mode 100644 changelogs/fragments/7842.yml diff --git a/changelogs/fragments/7842.yml b/changelogs/fragments/7842.yml new file mode 100644 index 000000000000..210ae0638c64 --- /dev/null +++ b/changelogs/fragments/7842.yml @@ -0,0 +1,2 @@ +refactor: +- [Workspace] Use small button, small padding and compressed. ([#7842](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7842)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx index 5a32d1534ce4..d9bfef12d5ab 100644 --- a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx +++ b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.tsx @@ -10,7 +10,6 @@ import { EuiPanel, EuiAvatar, EuiSpacer, - EuiButton, EuiPopover, EuiFlexItem, EuiModalBody, @@ -20,6 +19,7 @@ import { EuiModalHeader, EuiContextMenu, EuiModalHeaderTitle, + EuiSmallButton, } from '@elastic/eui'; import React, { useMemo, useState } from 'react'; import { i18n } from '@osd/i18n'; @@ -88,7 +88,7 @@ export const UseCaseFooter = ({ return ( <> - + {isModalVisible && ( @@ -108,13 +108,16 @@ export const UseCaseFooter = ({ - + {i18n.translate('workspace.useCase.footer.modal.close', { defaultMessage: 'Close', })} - + {isDashboardAdmin && ( - + )} @@ -138,9 +141,9 @@ export const UseCaseFooter = ({ basePath ); return ( - + {i18n.translate('workspace.useCase.footer.openWorkspace', { defaultMessage: 'Open' })} - + ); } @@ -176,11 +179,11 @@ export const UseCaseFooter = ({ }; const button = ( - + {i18n.translate('workspace.useCase.footer.selectWorkspace', { defaultMessage: 'Select workspace', })} - + ); const panels = [ { @@ -195,7 +198,7 @@ export const UseCaseFooter = ({ button={button} isOpen={isPopoverOpen} closePopover={closePopover} - panelPaddingSize="none" + panelPaddingSize="s" anchorPosition="downCenter" > diff --git a/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap b/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap index b1036d4d80ed..cf670fddf4df 100644 --- a/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap +++ b/src/plugins/workspace/public/components/workspace_detail/__snapshots__/workspace_detail.test.tsx.snap @@ -445,7 +445,7 @@ exports[`WorkspaceDetail render workspace detail page normally 1`] = ` value="observability" />
- + - - + handleAssignDataSources(selectedDataSources)} isDisabled={!selectedDataSources || selectedDataSources.length === 0} fill @@ -114,7 +114,7 @@ export const AssociationDataSourceModal = ({ id="workspace.detail.dataSources.associateModal.save.button" defaultMessage="Save changes" /> - + ); diff --git a/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx b/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx index 278b7ffcba85..57cffab2e1c8 100644 --- a/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx +++ b/src/plugins/workspace/public/components/workspace_detail/opensearch_connections_table.tsx @@ -6,7 +6,7 @@ import React, { useMemo, useState } from 'react'; import { EuiSpacer, - EuiButton, + EuiSmallButton, EuiFlexItem, EuiFlexGroup, EuiFieldSearch, @@ -160,7 +160,7 @@ export const OpenSearchConnectionTable = ({ {selectedItems.length > 0 && !modalVisible && ( - setModalVisible(true)} data-test-subj="workspace-detail-dataSources-table-bulkRemove" @@ -169,7 +169,7 @@ export const OpenSearchConnectionTable = ({ defaultMessage: 'Remove {numberOfSelect} association(s)', values: { numberOfSelect: selectedItems.length }, })} - + )} diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx index ec79f063acc5..3de52f3aabff 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx @@ -4,8 +4,8 @@ */ import { - EuiSuperSelect, - EuiColorPicker, + EuiCompressedSuperSelect, + EuiCompressedColorPicker, EuiCompressedFormRow, EuiDescribedFormGroup, } from '@elastic/eui'; @@ -104,7 +104,7 @@ export const WorkspaceDetailFormDetails = ({ error={formErrors.features?.message} helpText={detailsUseCaseHelpText} > - { @@ -125,7 +125,7 @@ export const WorkspaceDetailFormDetails = ({ isInvalid={!!formErrors.color} error={formErrors.color?.message} > -
`; - -exports[` should render correctly 1`] = ` -
-
- -
-
-`; diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_groups.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_groups.test.tsx.snap new file mode 100644 index 000000000000..3d923a49dd80 --- /dev/null +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_groups.test.tsx.snap @@ -0,0 +1,204 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` should render correctly 1`] = ` +
+
+ +
+
+`; diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index 168407a7de4f..88f06ee9edcb 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -160,43 +160,6 @@ exports[`Header handles visibility and lock changes 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -6358,43 +6321,6 @@ exports[`Header handles visibility and lock changes 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -7346,43 +7272,6 @@ exports[`Header renders application header without title and breadcrumbs 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -9331,43 +9220,6 @@ exports[`Header renders application header without title and breadcrumbs 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -9853,43 +9705,6 @@ exports[`Header renders condensed header 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -14822,43 +14637,6 @@ exports[`Header renders condensed header 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -15307,43 +15085,6 @@ exports[`Header renders page header with application title 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -18669,43 +18410,6 @@ exports[`Header renders page header with application title 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -19191,43 +18895,6 @@ exports[`Header toggles primary navigation menu when clicked 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, @@ -24160,43 +23827,6 @@ exports[`Header toggles primary navigation menu when clicked 1`] = ` "syncErrorThrown": false, "syncErrorValue": null, }, - Subscriber { - "_parentOrParents": null, - "_subscriptions": Array [ - SubjectSubscription { - "_parentOrParents": [Circular], - "_subscriptions": null, - "closed": false, - "subject": [Circular], - "subscriber": [Circular], - }, - ], - "closed": false, - "destination": SafeSubscriber { - "_complete": undefined, - "_context": [Circular], - "_error": undefined, - "_next": [Function], - "_parentOrParents": null, - "_parentSubscriber": [Circular], - "_subscriptions": null, - "closed": false, - "destination": Object { - "closed": true, - "complete": [Function], - "error": [Function], - "next": [Function], - }, - "isStopped": false, - "syncErrorThrowable": false, - "syncErrorThrown": false, - "syncErrorValue": null, - }, - "isStopped": false, - "syncErrorThrowable": true, - "syncErrorThrown": false, - "syncErrorValue": null, - }, ], "thrownError": null, }, diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx index 98b2ade3e257..418dca694e21 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.test.tsx @@ -10,13 +10,17 @@ import { StubBrowserStorage } from 'test_utils/stub_browser_storage'; import { CollapsibleNavGroupEnabled, CollapsibleNavGroupEnabledProps, - NavGroups, } from './collapsible_nav_group_enabled'; import { ChromeNavLink } from '../../nav_links'; -import { ChromeRegistrationNavLink, NavGroupItemInMap } from '../../nav_group'; +import { NavGroupItemInMap } from '../../nav_group'; import { httpServiceMock } from '../../../mocks'; import { getLogos } from '../../../../common'; -import { ALL_USE_CASE_ID, DEFAULT_NAV_GROUPS, WorkspaceObject } from '../../../../public'; +import { + ALL_USE_CASE_ID, + DEFAULT_APP_CATEGORIES, + DEFAULT_NAV_GROUPS, + WorkspaceObject, +} from '../../../../public'; import { capabilitiesServiceMock } from '../../../application/capabilities/capabilities_service.mock'; jest.mock('./collapsible_nav_group_enabled_top', () => ({ @@ -25,75 +29,6 @@ jest.mock('./collapsible_nav_group_enabled_top', () => ({ const mockBasePath = httpServiceMock.createSetupContract({ basePath: '/test' }).basePath; -describe('', () => { - const getMockedNavLink = ( - navLink: Partial - ): ChromeNavLink & ChromeRegistrationNavLink => ({ - baseUrl: '', - href: '', - id: '', - title: '', - ...navLink, - }); - it('should render correctly', () => { - const navigateToApp = jest.fn(); - const onNavItemClick = jest.fn(); - const { container, getByTestId, queryByTestId } = render( - - ); - expect(container).toMatchSnapshot(); - expect(container.querySelectorAll('.nav-link-item-btn').length).toEqual(5); - fireEvent.click(getByTestId('collapsibleNavAppLink-pure')); - expect(navigateToApp).toBeCalledTimes(0); - // The accordion is collapsed - expect(queryByTestId('collapsibleNavAppLink-subLink')).toBeNull(); - - // Expand the accordion - fireEvent.click(getByTestId('collapsibleNavAppLink-pure')); - fireEvent.click(getByTestId('collapsibleNavAppLink-subLink')); - expect(navigateToApp).toBeCalledWith('subLink'); - }); -}); - const defaultNavGroupMap = { [ALL_USE_CASE_ID]: { ...DEFAULT_NAV_GROUPS[ALL_USE_CASE_ID], @@ -342,4 +277,33 @@ describe('', () => { expect(getByTestId('collapsibleNavAppLink-link-in-essentials')).toBeInTheDocument(); expect(queryAllByTestId('collapsibleNavAppLink-link-in-all').length).toEqual(1); }); + + it('should render manage category when in all use case if workspace disabled', () => { + const props = mockProps({ + currentNavGroupId: ALL_USE_CASE_ID, + navGroupsMap: { + ...defaultNavGroupMap, + [DEFAULT_NAV_GROUPS.dataAdministration.id]: { + ...DEFAULT_NAV_GROUPS.dataAdministration, + navLinks: [ + { + id: 'link-in-dataAdministration', + title: 'link-in-dataAdministration', + }, + ], + }, + }, + navLinks: [ + { + id: 'link-in-dataAdministration', + title: 'link-in-dataAdministration', + baseUrl: '', + href: '', + }, + ], + }); + const { getByText } = render(); + // Should render manage category + expect(getByText(DEFAULT_APP_CATEGORIES.manage.label)).toBeInTheDocument(); + }); }); diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx index d196e760e43b..d8867d973d7d 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx @@ -4,15 +4,7 @@ */ import './collapsible_nav_group_enabled.scss'; -import { - EuiFlexItem, - EuiFlyout, - EuiSideNavItemType, - EuiSideNav, - EuiPanel, - EuiText, - EuiHorizontalRule, -} from '@elastic/eui'; +import { EuiFlyout, EuiPanel, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import React, { useMemo } from 'react'; import useObservable from 'react-use/lib/useObservable'; @@ -20,7 +12,7 @@ import * as Rx from 'rxjs'; import classNames from 'classnames'; import { WorkspacesStart } from 'src/core/public/workspace'; import { ChromeNavControl, ChromeNavLink } from '../..'; -import { AppCategory, NavGroupStatus } from '../../../../types'; +import { AppCategory, NavGroupType } from '../../../../types'; import { InternalApplicationStart } from '../../../application/types'; import { HttpStart } from '../../../http'; import { OnIsLockedUpdate } from './'; @@ -31,18 +23,15 @@ import { ChromeRegistrationNavLink, NavGroupItemInMap, } from '../../nav_group'; -import { - fulfillRegistrationLinksToChromeNavLinks, - getOrderedLinksOrCategories, - LinkItem, - LinkItemType, -} from '../../utils'; +import { fulfillRegistrationLinksToChromeNavLinks, getVisibleUseCases, sortBy } from '../../utils'; import { ALL_USE_CASE_ID, DEFAULT_APP_CATEGORIES } from '../../../../../core/utils'; import { CollapsibleNavTop } from './collapsible_nav_group_enabled_top'; import { HeaderNavControls } from './header_nav_controls'; +import { NavGroups } from './collapsible_nav_groups'; export interface CollapsibleNavGroupEnabledProps { appId$: InternalApplicationStart['currentAppId$']; + collapsibleNavHeaderRender?: () => JSX.Element | null; basePath: HttpStart['basePath']; id: string; isLocked: boolean; @@ -63,147 +52,16 @@ export interface CollapsibleNavGroupEnabledProps { currentWorkspace$: WorkspacesStart['currentWorkspace$']; } -interface NavGroupsProps { - navLinks: ChromeNavLink[]; - suffix?: React.ReactElement; - style?: React.CSSProperties; - appId?: string; - navigateToApp: InternalApplicationStart['navigateToApp']; - onNavItemClick: ( - event: React.MouseEvent, - navItem: ChromeNavLink - ) => void; -} - const titleForSeeAll = i18n.translate('core.ui.primaryNav.seeAllLabel', { defaultMessage: 'See all...', }); -const LEVEL_FOR_ROOT_ITEMS = 1; - -export function NavGroups({ - navLinks, - suffix, - style, - appId, - navigateToApp, - onNavItemClick, -}: NavGroupsProps) { - const createNavItem = ({ - link, - className, - }: { - link: ChromeNavLink; - className?: string; - }): EuiSideNavItemType<{}> => { - const euiListItem = createEuiListItem({ - link, - appId, - dataTestSubj: `collapsibleNavAppLink-${link.id}`, - navigateToApp, - onClick: (event) => { - onNavItemClick(event, link); - }, - }); - - return { - id: `${link.id}-${link.title}`, - name: {link.title}, - onClick: euiListItem.onClick, - href: euiListItem.href, - emphasize: euiListItem.isActive, - className: `nav-link-item ${className || ''}`, - buttonClassName: 'nav-link-item-btn', - 'data-test-subj': euiListItem['data-test-subj'], - 'aria-label': link.title, - }; - }; - const createSideNavItem = ( - navLink: LinkItem, - level: number, - className?: string - ): EuiSideNavItemType<{}> => { - if (navLink.itemType === LinkItemType.LINK) { - if (navLink.link.title === titleForSeeAll) { - const navItem = createNavItem({ - link: navLink.link, - }); - - return { - ...navItem, - name: {navItem.name}, - emphasize: false, - }; - } - - return createNavItem({ - link: navLink.link, - className, - }); - } - - if (navLink.itemType === LinkItemType.PARENT_LINK && navLink.link) { - const props = createNavItem({ link: navLink.link }); - const parentItem = { - ...props, - forceOpen: true, - /** - * The href and onClick should both be undefined to make parent item rendered as accordion. - */ - href: undefined, - onClick: undefined, - className: classNames(props.className, 'nav-link-parent-item'), - buttonClassName: classNames(props.buttonClassName, 'nav-link-parent-item-button'), - items: navLink.links.map((subNavLink) => - createSideNavItem(subNavLink, level + 1, 'nav-nested-item') - ), - }; - /** - * OuiSideBar will never render items of first level as accordion, - * in order to display accordion, we need to render a fake parent item. - */ - if (level === LEVEL_FOR_ROOT_ITEMS) { - return { - className: 'nav-link-fake-item', - buttonClassName: 'nav-link-fake-item-button', - name: '', - items: [parentItem], - id: `fake_${props.id}`, - }; - } - - return parentItem; - } - - if (navLink.itemType === LinkItemType.CATEGORY) { - return { - id: navLink.category?.id ?? '', - name:
{navLink.category?.label ?? ''}
, - items: navLink.links?.map((link) => createSideNavItem(link, level + 1)), - 'aria-label': navLink.category?.label, - }; - } - - return {} as EuiSideNavItemType<{}>; - }; - const orderedLinksOrCategories = getOrderedLinksOrCategories(navLinks); - const sideNavItems = orderedLinksOrCategories - .map((navLink) => createSideNavItem(navLink, LEVEL_FOR_ROOT_ITEMS)) - .filter((item): item is EuiSideNavItemType<{}> => !!item); - return ( - - - {suffix} - - ); -} - // Custom category is used for those features not belong to any of use cases in all use case. -// and the custom category should always sit before manage category +// and the custom category should always sit after manage category const customCategory: AppCategory = { id: 'custom', label: i18n.translate('core.ui.customNavList.label', { defaultMessage: 'Custom' }), - order: (DEFAULT_APP_CATEGORIES.manage.order || 0) - 500, + order: (DEFAULT_APP_CATEGORIES.manage.order || 0) + 500, }; enum NavWidth { @@ -224,6 +82,7 @@ export function CollapsibleNavGroupEnabled({ logos, setCurrentNavGroup, capabilities, + collapsibleNavHeaderRender, ...observables }: CollapsibleNavGroupEnabledProps) { const allNavLinks = useObservable(observables.navLinks$, []); @@ -241,73 +100,119 @@ export function CollapsibleNavGroupEnabled({ [navGroupsMap, navLinks] ); - const visibleUseCases = useMemo( - () => - Object.values(navGroupsMap).filter( - (group) => group.type === undefined && group.status !== NavGroupStatus.Hidden - ), - [navGroupsMap] - ); + const visibleUseCases = useMemo(() => getVisibleUseCases(navGroupsMap), [navGroupsMap]); - const navLinksForRender: ChromeNavLink[] = useMemo(() => { - if (currentNavGroup && currentNavGroup.id !== ALL_USE_CASE_ID) { - return fulfillRegistrationLinksToChromeNavLinks( - navGroupsMap[currentNavGroup.id].navLinks || [], - navLinks - ); - } + const currentNavGroupId = useMemo(() => { + if (!currentNavGroup) { + if (visibleUseCases.length === 1) { + return visibleUseCases[0].id; + } - if (visibleUseCases.length === 1) { - return fulfillRegistrationLinksToChromeNavLinks( - navGroupsMap[visibleUseCases[0].id].navLinks || [], - navLinks - ); + if (!capabilities.workspaces.enabled) { + return ALL_USE_CASE_ID; + } } - const navLinksForAll: ChromeRegistrationNavLink[] = []; + return currentNavGroup?.id; + }, [capabilities, currentNavGroup, visibleUseCases]); + + const shouldAppendManageCategory = capabilities.workspaces.enabled + ? !currentNavGroupId + : currentNavGroupId === ALL_USE_CASE_ID; + + const shouldShowCollapsedNavHeaderContent = + isNavOpen && !!collapsibleNavHeaderRender && !currentNavGroupId; + + const navLinksForRender: ChromeNavLink[] = useMemo(() => { + const getSystemNavGroups = () => { + const result: ChromeNavLink[] = []; + Object.values(navGroupsMap) + .sort(sortBy('order')) + .forEach((navGroup) => { + if (navGroup.type !== NavGroupType.SYSTEM) { + return; + } + const visibleNavLinksWithinNavGroup = fulfillRegistrationLinksToChromeNavLinks( + navGroup.navLinks, + navLinks + ); + /** + * We will take the first visible app inside the system nav groups + * when customers click the menu. If there is not a visible nav links, + * we should not show the nav group. + */ + if (visibleNavLinksWithinNavGroup[0]) { + result.push({ + ...visibleNavLinksWithinNavGroup[0], + title: navGroup.title, + category: DEFAULT_APP_CATEGORIES.manage, + }); + } + }); + + return result; + }; + + const navLinksResult: ChromeRegistrationNavLink[] = []; - // Append all the links that do not have use case info to keep backward compatible - const linkIdsWithUseGroupInfo = Object.values(navGroupsMap).reduce((total, navGroup) => { - return [...total, ...navGroup.navLinks.map((navLink) => navLink.id)]; - }, [] as string[]); - navLinks - .filter((link) => !linkIdsWithUseGroupInfo.includes(link.id)) - .forEach((navLink) => { - navLinksForAll.push({ + if (currentNavGroupId && currentNavGroupId !== ALL_USE_CASE_ID) { + navLinksResult.push(...(navGroupsMap[currentNavGroupId].navLinks || [])); + } + + if (currentNavGroupId === ALL_USE_CASE_ID) { + // Append all the links that do not have use case info to keep backward compatible + const linkIdsWithNavGroupInfo = Object.values(navGroupsMap).reduce((total, navGroup) => { + return [...total, ...navGroup.navLinks.map((navLink) => navLink.id)]; + }, [] as string[]); + navLinks.forEach((navLink) => { + if (linkIdsWithNavGroupInfo.includes(navLink.id)) { + return; + } + navLinksResult.push({ ...navLink, category: customCategory, }); }); - // Append all the links registered to all use case - navGroupsMap[ALL_USE_CASE_ID]?.navLinks.forEach((navLink) => { - navLinksForAll.push(navLink); - }); + // Append all the links registered to all use case + navGroupsMap[ALL_USE_CASE_ID]?.navLinks.forEach((navLink) => { + navLinksResult.push(navLink); + }); - // Append use case section into left navigation - Object.values(navGroupsMap) - .filter((group) => !group.type) - .forEach((group) => { + // Append use case section into left navigation + Object.values(navGroupsMap).forEach((group) => { + if (group.type) { + return; + } const categoryInfo = { id: group.id, label: group.title, order: group.order, }; - const linksForAllUseCaseWithinNavGroup = fulfillRegistrationLinksToChromeNavLinks( + + const fulfilledLinksOfNavGroup = fulfillRegistrationLinksToChromeNavLinks( group.navLinks, navLinks - ) - .filter((navLink) => navLink.showInAllNavGroup) - .map((navLink) => ({ + ); + + const linksForAllUseCaseWithinNavGroup: ChromeRegistrationNavLink[] = []; + + fulfilledLinksOfNavGroup.forEach((navLink) => { + if (!navLink.showInAllNavGroup) { + return; + } + + linksForAllUseCaseWithinNavGroup.push({ ...navLink, category: categoryInfo, - })); + }); + }); - navLinksForAll.push(...linksForAllUseCaseWithinNavGroup); + navLinksResult.push(...linksForAllUseCaseWithinNavGroup); if (linksForAllUseCaseWithinNavGroup.length) { - navLinksForAll.push({ - id: group.navLinks[0].id, + navLinksResult.push({ + id: fulfilledLinksOfNavGroup[0].id, title: titleForSeeAll, order: Number.MAX_SAFE_INTEGER, category: categoryInfo, @@ -317,22 +222,26 @@ export function CollapsibleNavGroupEnabled({ * Find if there are any links inside a use case but without a `see all` entry. * If so, append these features into custom category as a fallback */ - fulfillRegistrationLinksToChromeNavLinks(group.navLinks, navLinks) - // Filter out links that already exists in all use case - .filter( - (navLink) => !navLinksForAll.find((navLinkInAll) => navLinkInAll.id === navLink.id) - ) - .forEach((navLink) => { - navLinksForAll.push({ - ...navLink, - category: customCategory, - }); + fulfillRegistrationLinksToChromeNavLinks(group.navLinks, navLinks).forEach((navLink) => { + // Links that already exists in all use case do not need to reappend + if (navLinksResult.find((navLinkInAll) => navLinkInAll.id === navLink.id)) { + return; + } + navLinksResult.push({ + ...navLink, + category: customCategory, }); + }); } }); + } + + if (shouldAppendManageCategory) { + navLinksResult.push(...getSystemNavGroups()); + } - return fulfillRegistrationLinksToChromeNavLinks(navLinksForAll, navLinks); - }, [navLinks, navGroupsMap, currentNavGroup, visibleUseCases]); + return fulfillRegistrationLinksToChromeNavLinks(navLinksResult, navLinks); + }, [navLinks, navGroupsMap, currentNavGroupId, shouldAppendManageCategory]); const width = useMemo(() => { if (!isNavOpen) { @@ -398,7 +307,7 @@ export function CollapsibleNavGroupEnabled({ navigateToApp={navigateToApp} logos={logos} setCurrentNavGroup={setCurrentNavGroup} - currentNavGroup={currentNavGroup} + currentNavGroup={currentNavGroupId ? navGroupsMap[currentNavGroupId] : undefined} shouldShrinkNavigation={!isNavOpen} onClickShrink={closeNav} visibleUseCases={visibleUseCases} @@ -414,6 +323,12 @@ export function CollapsibleNavGroupEnabled({ hasShadow={false} className="eui-yScroll flex-1-container" > + {shouldShowCollapsedNavHeaderContent && collapsibleNavHeaderRender ? ( + <> + {collapsibleNavHeaderRender()} + + + ) : null} ', () => { currentWorkspace$: new BehaviorSubject({ id: 'foo', name: 'foo' }), visibleUseCases: [ { - id: 'navGroupFoo', + id: ALL_USE_CASE_ID, title: 'navGroupFoo', description: 'navGroupFoo', navLinks: [], }, - { - id: 'navGroupBar', - title: 'navGroupBar', - description: 'navGroupBar', - navLinks: [], - }, ], currentNavGroup: { id: 'navGroupFoo', diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.tsx index 23e2f7e6108c..067fb2ffd2e1 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled_top.tsx @@ -56,7 +56,9 @@ export const CollapsibleNavTop = ({ * 3. current nav group is not all use case */ const isInsideSecondLevelOfAllWorkspace = - visibleUseCases.length > 1 && !!currentWorkspace && currentNavGroup?.id !== ALL_USE_CASE_ID; + !!currentWorkspace && + visibleUseCases[0].id === ALL_USE_CASE_ID && + currentNavGroup?.id !== ALL_USE_CASE_ID; const shouldShowBackButton = !shouldShrinkNavigation && isInsideSecondLevelOfAllWorkspace; const shouldShowHomeLink = !shouldShrinkNavigation && !shouldShowBackButton; diff --git a/src/core/public/chrome/ui/header/collapsible_nav_groups.test.tsx b/src/core/public/chrome/ui/header/collapsible_nav_groups.test.tsx new file mode 100644 index 000000000000..75865190cad8 --- /dev/null +++ b/src/core/public/chrome/ui/header/collapsible_nav_groups.test.tsx @@ -0,0 +1,79 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import { NavGroups } from './collapsible_nav_groups'; +import { ChromeRegistrationNavLink } from '../../nav_group'; +import { ChromeNavLink } from '../../nav_links'; + +describe('', () => { + const getMockedNavLink = ( + navLink: Partial + ): ChromeNavLink & ChromeRegistrationNavLink => ({ + baseUrl: '', + href: '', + id: '', + title: '', + ...navLink, + }); + it('should render correctly', () => { + const navigateToApp = jest.fn(); + const onNavItemClick = jest.fn(); + const { container, getByTestId, queryByTestId } = render( + + ); + expect(container).toMatchSnapshot(); + expect(container.querySelectorAll('.nav-link-item-btn').length).toEqual(5); + fireEvent.click(getByTestId('collapsibleNavAppLink-pure')); + expect(navigateToApp).toBeCalledTimes(0); + // The accordion is collapsed + expect(queryByTestId('collapsibleNavAppLink-subLink')).toBeNull(); + + // Expand the accordion + fireEvent.click(getByTestId('collapsibleNavAppLink-pure')); + fireEvent.click(getByTestId('collapsibleNavAppLink-subLink')); + expect(navigateToApp).toBeCalledWith('subLink'); + }); +}); diff --git a/src/core/public/chrome/ui/header/collapsible_nav_groups.tsx b/src/core/public/chrome/ui/header/collapsible_nav_groups.tsx new file mode 100644 index 000000000000..53a75aeaaddd --- /dev/null +++ b/src/core/public/chrome/ui/header/collapsible_nav_groups.tsx @@ -0,0 +1,150 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import './collapsible_nav_group_enabled.scss'; +import { EuiFlexItem, EuiSideNavItemType, EuiSideNav, EuiText } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import React from 'react'; +import classNames from 'classnames'; +import { ChromeNavLink } from '../..'; +import { InternalApplicationStart } from '../../../application/types'; +import { createEuiListItem } from './nav_link'; +import { getOrderedLinksOrCategories, LinkItem, LinkItemType } from '../../utils'; + +export interface NavGroupsProps { + navLinks: ChromeNavLink[]; + suffix?: React.ReactElement; + style?: React.CSSProperties; + appId?: string; + navigateToApp: InternalApplicationStart['navigateToApp']; + onNavItemClick: ( + event: React.MouseEvent, + navItem: ChromeNavLink + ) => void; +} + +const titleForSeeAll = i18n.translate('core.ui.primaryNav.seeAllLabel', { + defaultMessage: 'See all...', +}); + +const LEVEL_FOR_ROOT_ITEMS = 1; + +export function NavGroups({ + navLinks, + suffix, + style, + appId, + navigateToApp, + onNavItemClick, +}: NavGroupsProps) { + const createNavItem = ({ + link, + className, + }: { + link: ChromeNavLink; + className?: string; + }): EuiSideNavItemType<{}> => { + const euiListItem = createEuiListItem({ + link, + appId, + dataTestSubj: `collapsibleNavAppLink-${link.id}`, + navigateToApp, + onClick: (event) => { + onNavItemClick(event, link); + }, + }); + + return { + id: `${link.id}-${link.title}`, + name: {link.title}, + onClick: euiListItem.onClick, + href: euiListItem.href, + emphasize: euiListItem.isActive, + className: `nav-link-item ${className || ''}`, + buttonClassName: 'nav-link-item-btn', + 'data-test-subj': euiListItem['data-test-subj'], + 'aria-label': link.title, + }; + }; + const createSideNavItem = ( + navLink: LinkItem, + level: number, + className?: string + ): EuiSideNavItemType<{}> => { + if (navLink.itemType === LinkItemType.LINK) { + if (navLink.link.title === titleForSeeAll) { + const navItem = createNavItem({ + link: navLink.link, + }); + + return { + ...navItem, + name: {navItem.name}, + emphasize: false, + }; + } + + return createNavItem({ + link: navLink.link, + className, + }); + } + + if (navLink.itemType === LinkItemType.PARENT_LINK && navLink.link) { + const props = createNavItem({ link: navLink.link }); + const parentItem = { + ...props, + forceOpen: true, + /** + * The href and onClick should both be undefined to make parent item rendered as accordion. + */ + href: undefined, + onClick: undefined, + className: classNames(props.className, 'nav-link-parent-item'), + buttonClassName: classNames(props.buttonClassName, 'nav-link-parent-item-button'), + items: navLink.links.map((subNavLink) => + createSideNavItem(subNavLink, level + 1, 'nav-nested-item') + ), + }; + /** + * OuiSideBar will never render items of first level as accordion, + * in order to display accordion, we need to render a fake parent item. + */ + if (level === LEVEL_FOR_ROOT_ITEMS) { + return { + className: 'nav-link-fake-item', + buttonClassName: 'nav-link-fake-item-button', + name: '', + items: [parentItem], + id: `fake_${props.id}`, + }; + } + + return parentItem; + } + + if (navLink.itemType === LinkItemType.CATEGORY) { + return { + id: navLink.category?.id ?? '', + name:
{navLink.category?.label ?? ''}
, + items: navLink.links?.map((link) => createSideNavItem(link, level + 1)), + 'aria-label': navLink.category?.label, + }; + } + + return {} as EuiSideNavItemType<{}>; + }; + const orderedLinksOrCategories = getOrderedLinksOrCategories(navLinks); + const sideNavItems = orderedLinksOrCategories + .map((navLink) => createSideNavItem(navLink, LEVEL_FOR_ROOT_ITEMS)) + .filter((navItem) => !!navItem.id); + + return ( + + + {suffix} + + ); +} diff --git a/src/core/public/chrome/ui/header/header.test.tsx b/src/core/public/chrome/ui/header/header.test.tsx index 9cc8652c3e41..7edf893826ac 100644 --- a/src/core/public/chrome/ui/header/header.test.tsx +++ b/src/core/public/chrome/ui/header/header.test.tsx @@ -194,24 +194,6 @@ describe('Header', () => { expect(component.find('CollapsibleNavGroupEnabled').exists()).toBeTruthy(); }); - it('show hide expand icon in top left navigation when workspace enabled + homepage + new navigation enabled', () => { - const branding = { - useExpandedHeader: false, - }; - const props = { - ...mockProps(), - branding, - }; - props.application.currentAppId$ = new BehaviorSubject('home'); - props.application.capabilities = { ...props.application.capabilities }; - (props.application.capabilities.workspaces as Record) = {}; - (props.application.capabilities.workspaces as Record).enabled = true; - - const component = mountWithIntl(
); - - expect(component.find('.header__toggleNavButtonSection').exists()).toBeFalsy(); - }); - it('toggles primary navigation menu when clicked', () => { const branding = { useExpandedHeader: false, diff --git a/src/core/public/chrome/ui/header/header.tsx b/src/core/public/chrome/ui/header/header.tsx index 492d9c7b3e78..6fa8d9a43a75 100644 --- a/src/core/public/chrome/ui/header/header.tsx +++ b/src/core/public/chrome/ui/header/header.tsx @@ -138,18 +138,10 @@ export function Header({ const isVisible = useObservable(observables.isVisible$, false); const headerVariant = useObservable(observables.headerVariant$, HeaderVariant.PAGE); const isLocked = useObservable(observables.isLocked$, false); - const appId = useObservable(application.currentAppId$, ''); const [isNavOpen, setIsNavOpen] = useState(false); const sidecarConfig = useObservable(observables.sidecarConfig$, undefined); const breadcrumbs = useObservable(observables.breadcrumbs$, []); - /** - * This is a workaround on 2.16 to hide the navigation items within left navigation - * when user is in homepage with workspace enabled + new navigation enabled - */ - const shouldHideExpandIcon = - navGroupEnabled && appId === 'home' && application.capabilities.workspaces.enabled; - const sidecarPaddingStyle = useMemo(() => { return getOsdSidecarPaddingStyle(sidecarConfig); }, [sidecarConfig]); @@ -365,11 +357,9 @@ export function Header({ const renderLegacyHeader = () => ( - {shouldHideExpandIcon ? null : ( - - {renderNavToggle()} - - )} + + {renderNavToggle()} + {renderLeftControls()} @@ -402,7 +392,7 @@ export function Header({ const renderPageHeader = () => (
- {shouldHideExpandIcon || isNavOpen ? null : renderNavToggle()} + {isNavOpen ? null : renderNavToggle()} {renderRecentItems()} @@ -450,7 +440,7 @@ export function Header({ const renderApplicationHeader = () => (
- {shouldHideExpandIcon || isNavOpen ? null : renderNavToggle()} + {isNavOpen ? null : renderNavToggle()} {renderRecentItems()} {renderActionMenu()} @@ -475,10 +465,11 @@ export function Header({ {navGroupEnabled ? ( = keyof T; -const sortBy = (key: KeyOf) => { +export const sortBy = (key: KeyOf) => { return (a: T, b: T): number => (a[key] > b[key] ? 1 : b[key] > a[key] ? -1 : 0); }; @@ -214,3 +215,9 @@ export const getSortedNavLinks = ( ); return acc; }; + +export const getVisibleUseCases = (navGroupMap: Record) => { + return Object.values(navGroupMap).filter( + (navGroup) => navGroup.status !== NavGroupStatus.Hidden && navGroup.type === undefined + ); +}; diff --git a/src/plugins/data_explorer/public/plugin.ts b/src/plugins/data_explorer/public/plugin.ts index 3b953567fbe8..d2c8da53a697 100644 --- a/src/plugins/data_explorer/public/plugin.ts +++ b/src/plugins/data_explorer/public/plugin.ts @@ -13,6 +13,7 @@ import { AppNavLinkStatus, ScopedHistory, AppUpdater, + DEFAULT_NAV_GROUPS, } from '../../../core/public'; import { DataExplorerPluginSetup, @@ -123,6 +124,41 @@ export class DataExplorerPlugin }, }); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ + { + id: PLUGIN_ID, + order: 301, // The nav link should be put behind discover + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ + { + id: PLUGIN_ID, + order: 301, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.essentials, [ + { + id: PLUGIN_ID, + order: 201, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [ + { + id: PLUGIN_ID, + order: 201, + }, + ]); + + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ + { + id: PLUGIN_ID, + order: 201, + }, + ]); + return { ...this.viewService.setup(), }; diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index 8e32537d0a0b..ac5f4c508821 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -65,7 +65,6 @@ import { PLUGIN_ID, HOME_APP_BASE_PATH, IMPORT_SAMPLE_DATA_APP_ID } from '../com import { DataSourcePluginStart } from '../../data_source/public'; import { workWithDataSection } from './application/components/homepage/sections/work_with_data'; import { learnBasicsSection } from './application/components/homepage/sections/learn_basics'; -import { DEFAULT_NAV_GROUPS } from '../../../core/public'; import { ContentManagementPluginSetup, ContentManagementPluginStart, diff --git a/src/plugins/index_pattern_management/public/plugin.test.ts b/src/plugins/index_pattern_management/public/plugin.test.ts index ec9a6137ffcf..4947c3d2749a 100644 --- a/src/plugins/index_pattern_management/public/plugin.test.ts +++ b/src/plugins/index_pattern_management/public/plugin.test.ts @@ -12,6 +12,7 @@ import { ManagementAppMountParams, RegisterManagementAppArgs, } from 'src/plugins/management/public'; +import { waitFor } from '@testing-library/dom'; describe('DiscoverPlugin', () => { it('setup successfully', () => { @@ -25,7 +26,9 @@ describe('DiscoverPlugin', () => { }) ).not.toThrow(); expect(setupMock.application.register).toBeCalledTimes(1); - expect(setupMock.chrome.navGroup.addNavLinksToGroup).toBeCalledTimes(1); + waitFor(() => { + expect(setupMock.chrome.navGroup.addNavLinksToGroup).toBeCalledTimes(1); + }); }); it('when new navigation is enabled, should navigate to standard IPM app', async () => { diff --git a/src/plugins/index_pattern_management/public/plugin.ts b/src/plugins/index_pattern_management/public/plugin.ts index d74cdaffe97e..b64e81a92151 100644 --- a/src/plugins/index_pattern_management/public/plugin.ts +++ b/src/plugins/index_pattern_management/public/plugin.ts @@ -167,13 +167,23 @@ export class IndexPatternManagementPlugin }, }); - core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [ - { - id: IPM_APP_ID, - title: sectionsHeader, - order: 400, - }, - ]); + core.getStartServices().then(([coreStart]) => { + /** + * The `capabilities.workspaces.enabled` indicates + * if workspace feature flag is turned on or not and + * the global index pattern management page should only be registered + * to settings and setup when workspace is turned off, + */ + if (!coreStart.application.capabilities.workspaces.enabled) { + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [ + { + id: IPM_APP_ID, + title: sectionsHeader, + order: 400, + }, + ]); + } + }); return this.indexPatternManagementService.setup({ httpClient: core.http }); } diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx index 4c5fb9f0e9d2..d2ce42ed6097 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx @@ -4,48 +4,33 @@ */ import { i18n } from '@osd/i18n'; -import React, { useMemo, useState } from 'react'; +import React, { useState } from 'react'; import { useObservable } from 'react-use'; import { EuiText, EuiPanel, - EuiTitle, EuiAvatar, EuiPopover, EuiToolTip, EuiFlexItem, EuiFlexGroup, - EuiListGroup, EuiSmallButtonIcon, EuiSmallButtonEmpty, - EuiListGroupItem, EuiSmallButton, } from '@elastic/eui'; import { BehaviorSubject } from 'rxjs'; -import { - WORKSPACE_CREATE_APP_ID, - WORKSPACE_LIST_APP_ID, - MAX_WORKSPACE_PICKER_NUM, -} from '../../../common/constants'; +import { WORKSPACE_CREATE_APP_ID, WORKSPACE_LIST_APP_ID } from '../../../common/constants'; import { CoreStart, WorkspaceObject } from '../../../../../core/public'; -import { getFirstUseCaseOfFeatureConfigs, getUseCaseUrl } from '../../utils'; -import { recentWorkspaceManager } from '../../recent_workspace_manager'; +import { getFirstUseCaseOfFeatureConfigs } from '../../utils'; import { WorkspaceUseCase } from '../../types'; import { navigateToWorkspaceDetail } from '../utils/workspace'; import { validateWorkspaceColor } from '../../../common/utils'; +import { WorkspacePickerContent } from '../workspace_picker_content/workspace_picker_content'; const defaultHeaderName = i18n.translate('workspace.menu.defaultHeaderName', { defaultMessage: 'Workspaces', }); -const allWorkspacesTitle = i18n.translate('workspace.menu.title.allWorkspaces', { - defaultMessage: 'All workspaces', -}); - -const recentWorkspacesTitle = i18n.translate('workspace.menu.title.recentWorkspaces', { - defaultMessage: 'Recent workspaces', -}); - const createWorkspaceButton = i18n.translate('workspace.menu.button.createWorkspace', { defaultMessage: 'Create workspace', }); @@ -73,22 +58,9 @@ interface Props { export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { const [isPopoverOpen, setPopover] = useState(false); const currentWorkspace = useObservable(coreStart.workspaces.currentWorkspace$, null); - const workspaceList = useObservable(coreStart.workspaces.workspaceList$, []); const isDashboardAdmin = coreStart.application.capabilities?.dashboards?.isDashboardAdmin; const availableUseCases = useObservable(registeredUseCases$, []); - const filteredWorkspaceList = useMemo(() => { - return workspaceList.slice(0, MAX_WORKSPACE_PICKER_NUM); - }, [workspaceList]); - - const filteredRecentWorkspaces = useMemo(() => { - return recentWorkspaceManager - .getRecentWorkspaces() - .map((workspace) => workspaceList.find((ws) => ws.id === workspace.id)) - .filter((workspace): workspace is WorkspaceObject => workspace !== undefined) - .slice(0, MAX_WORKSPACE_PICKER_NUM); - }, [workspaceList]); - const currentWorkspaceName = currentWorkspace?.name ?? defaultHeaderName; const getUseCase = (workspace: WorkspaceObject) => { @@ -130,46 +102,6 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { /> ); - const getWorkspaceListGroup = (filterWorkspaceList: WorkspaceObject[], itemType: string) => { - const listItems = filterWorkspaceList.map((workspace: WorkspaceObject) => { - const useCase = getUseCase(workspace); - const useCaseURL = getUseCaseUrl(useCase, workspace, coreStart.application, coreStart.http); - return ( - - } - label={workspace.name} - onClick={() => { - closePopover(); - window.location.assign(useCaseURL); - }} - /> - ); - }); - return ( - <> - -

{itemType === 'all' ? allWorkspacesTitle : recentWorkspacesTitle}

-
- - {listItems} - - - ); - }; - return ( { - {filteredRecentWorkspaces.length > 0 && - getWorkspaceListGroup(filteredRecentWorkspaces, 'recent')} - {filteredWorkspaceList.length > 0 && getWorkspaceListGroup(filteredWorkspaceList, 'all')} + setPopover(false)} + /> diff --git a/src/plugins/workspace/public/components/workspace_picker_content/workspace_picker_content.tsx b/src/plugins/workspace/public/components/workspace_picker_content/workspace_picker_content.tsx new file mode 100644 index 000000000000..4dace89ea119 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_picker_content/workspace_picker_content.tsx @@ -0,0 +1,111 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import React, { useMemo } from 'react'; +import { useObservable } from 'react-use'; +import { EuiTitle, EuiAvatar, EuiListGroup, EuiListGroupItem } from '@elastic/eui'; +import { BehaviorSubject } from 'rxjs'; +import { MAX_WORKSPACE_PICKER_NUM } from '../../../common/constants'; +import { CoreStart, WorkspaceObject } from '../../../../../core/public'; +import { recentWorkspaceManager } from '../../recent_workspace_manager'; +import { WorkspaceUseCase } from '../../types'; +import { validateWorkspaceColor } from '../../../common/utils'; +import { getFirstUseCaseOfFeatureConfigs, getUseCaseUrl } from '../../utils'; + +const allWorkspacesTitle = i18n.translate('workspace.menu.title.allWorkspaces', { + defaultMessage: 'All workspaces', +}); + +const recentWorkspacesTitle = i18n.translate('workspace.menu.title.recentWorkspaces', { + defaultMessage: 'Recent workspaces', +}); + +const getValidWorkspaceColor = (color?: string) => + validateWorkspaceColor(color) ? color : undefined; + +interface Props { + coreStart: CoreStart; + registeredUseCases$: BehaviorSubject; + onClickWorkspace?: () => void; +} + +export const WorkspacePickerContent = ({ + coreStart, + registeredUseCases$, + onClickWorkspace, +}: Props) => { + const workspaceList = useObservable(coreStart.workspaces.workspaceList$, []); + const availableUseCases = useObservable(registeredUseCases$, []); + + const filteredWorkspaceList = useMemo(() => { + return workspaceList.slice(0, MAX_WORKSPACE_PICKER_NUM); + }, [workspaceList]); + + const filteredRecentWorkspaces = useMemo(() => { + return recentWorkspaceManager + .getRecentWorkspaces() + .map((workspace) => workspaceList.find((ws) => ws.id === workspace.id)) + .filter((workspace): workspace is WorkspaceObject => workspace !== undefined) + .slice(0, MAX_WORKSPACE_PICKER_NUM); + }, [workspaceList]); + + const getUseCase = (workspace: WorkspaceObject) => { + if (!workspace.features) { + return; + } + const useCaseId = getFirstUseCaseOfFeatureConfigs(workspace.features); + return availableUseCases.find((useCase) => useCase.id === useCaseId); + }; + + const getWorkspaceListGroup = (filterWorkspaceList: WorkspaceObject[], itemType: string) => { + const listItems = filterWorkspaceList.map((workspace: WorkspaceObject) => { + const useCase = getUseCase(workspace); + const useCaseURL = getUseCaseUrl(useCase, workspace, coreStart.application, coreStart.http); + return ( + + } + label={workspace.name} + onClick={() => { + onClickWorkspace?.(); + window.location.assign(useCaseURL); + }} + /> + ); + }); + return ( + + +

{itemType === 'all' ? allWorkspacesTitle : recentWorkspacesTitle}

+ + } + /> + {listItems} +
+ ); + }; + + return ( + <> + {filteredRecentWorkspaces.length > 0 && + getWorkspaceListGroup(filteredRecentWorkspaces, 'recent')} + {filteredWorkspaceList.length > 0 && getWorkspaceListGroup(filteredWorkspaceList, 'all')} + + ); +}; diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index 3be162a4522e..c6bc16e1c939 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -35,6 +35,7 @@ describe('Workspace plugin', () => { WorkspaceClientMock.mockClear(); Object.values(workspaceClientMock).forEach((item) => item.mockClear()); }); + it('#setup', async () => { const setupMock = getSetupMock(); const savedObjectManagementSetupMock = savedObjectsManagementPluginMock.createSetupContract(); @@ -218,6 +219,21 @@ describe('Workspace plugin', () => { ); }); + it('#setup should register registerCollapsibleNavHeader when new left nav is turned on', async () => { + const setupMock = coreMock.createSetup(); + let collapsibleNavHeaderImplementation = () => null; + setupMock.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); + setupMock.chrome.registerCollapsibleNavHeader.mockImplementation( + (func) => (collapsibleNavHeaderImplementation = func) + ); + const workspacePlugin = new WorkspacePlugin(); + await workspacePlugin.setup(setupMock, {}); + expect(collapsibleNavHeaderImplementation()).toEqual(null); + const startMock = coreMock.createStart(); + await workspacePlugin.start(startMock, mockDependencies); + expect(collapsibleNavHeaderImplementation()).not.toEqual(null); + }); + it('#setup should register workspace essential use case when new home is disabled', async () => { const setupMock = { ...coreMock.createSetup(), diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 03c6b544b64d..3e04e61a8404 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -7,7 +7,7 @@ import { BehaviorSubject, combineLatest, Subscription } from 'rxjs'; import React from 'react'; import { i18n } from '@osd/i18n'; import { map } from 'rxjs/operators'; -import { EuiIcon } from '@elastic/eui'; +import { EuiIcon, EuiPanel } from '@elastic/eui'; import { Plugin, CoreStart, @@ -61,6 +61,7 @@ import { UseCaseService } from './services/use_case_service'; import { WorkspaceListCard } from './components/service_card'; import { UseCaseFooter } from './components/home_get_start_card'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; +import { WorkspacePickerContent } from './components/workspace_picker_content/workspace_picker_content'; import { HOME_CONTENT_AREAS } from '../../../plugins/content_management/public'; import { registerEssentialOverviewContent, @@ -169,15 +170,13 @@ export class WorkspacePlugin * It checks the following conditions: * 1. The navigation group is not a system-level group. * 2. The current workspace has feature configurations set up. - * 3. The current workspace's use case is not "All use case". - * 4. The current navigation group is not included in the feature configurations of the workspace. + * 3. The current navigation group is not included in the feature configurations of the workspace. * * If all these conditions are true, it means that the navigation group should be hidden. */ if ( navGroup.type !== NavGroupType.SYSTEM && currentWorkspace.features && - getFirstUseCaseOfFeatureConfigs(currentWorkspace.features) !== ALL_USE_CASE_ID && !isNavGroupInFeatureConfigs(navGroup.id, currentWorkspace.features) ) { return { @@ -530,6 +529,28 @@ export class WorkspacePlugin }, ]); + if (core.chrome.navGroup.getNavGroupEnabled()) { + /** + * Show workspace picker content when outside of workspace and not in any nav group + */ + core.chrome.registerCollapsibleNavHeader(() => { + if (!this.coreStart) { + return null; + } + return React.createElement(EuiPanel, { + hasShadow: false, + hasBorder: false, + children: [ + React.createElement(WorkspacePickerContent, { + key: 'workspacePickerContent', + coreStart: this.coreStart, + registeredUseCases$: this.registeredUseCases$, + }), + ], + }); + }); + } + return {}; } From 8c779c15ef397feda3402aeaf7d200c0da8f64eb Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 22:01:16 +0800 Subject: [PATCH 251/276] tweaks the new homepage styles (#7875) (#7883) * tweaks homepage styles * Add key to React.Fragment --------- (cherry picked from commit 5e0ce2b07ed9338d83177d9c2b607b5cf7872c35) Signed-off-by: Yulong Ruan Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../public/components/page_render.tsx | 33 +++++++++---------- .../public/components/section_input.test.ts | 4 +++ .../public/components/section_input.ts | 3 ++ .../public/components/section_render.tsx | 4 +-- .../home_list_card.test.tsx.snap | 8 ++--- .../application/components/home_list_card.tsx | 6 ++-- .../home/public/application/home_render.tsx | 2 +- .../public/management_section/recent_work.tsx | 8 ++--- .../workspace_list_card.test.tsx.snap | 8 ++--- .../service_card/workspace_list_card.tsx | 6 ++-- 10 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/plugins/content_management/public/components/page_render.tsx b/src/plugins/content_management/public/components/page_render.tsx index 1a28d1efec2f..f0cdca8bd900 100644 --- a/src/plugins/content_management/public/components/page_render.tsx +++ b/src/plugins/content_management/public/components/page_render.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { useObservable } from 'react-use'; import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexItem, EuiPage, EuiSpacer } from '@elastic/eui'; import { Page } from '../services'; import { SectionRender } from './section_render'; import { EmbeddableStart } from '../../../embeddable/public'; @@ -22,22 +22,21 @@ export const PageRender = ({ page, embeddable, savedObjectsClient }: Props) => { const sections = useObservable(page.getSections$()) || []; return ( - - {sections.map((section) => ( - - - + + {sections.map((section, i) => ( + + + + + {i < sections.length - 1 && } + ))} - + ); }; diff --git a/src/plugins/content_management/public/components/section_input.test.ts b/src/plugins/content_management/public/components/section_input.test.ts index 80fe5ce0863c..bcf7db4a7ab8 100644 --- a/src/plugins/content_management/public/components/section_input.test.ts +++ b/src/plugins/content_management/public/components/section_input.test.ts @@ -21,6 +21,7 @@ test('it should create card section input', () => { id: 'section1', title: '', hidePanelTitles: true, + hidePanelActions: true, viewMode: 'view', panels: { content1: { @@ -55,6 +56,7 @@ test('it should create card section input with explicit input specified', () => id: 'section1', title: 'new title', hidePanelTitles: true, + hidePanelActions: true, viewMode: 'view', columns: 4, panels: { @@ -189,6 +191,7 @@ test('it should create dashboard input', async () => { content3: { explicitInput: { disabledActions: ['togglePanel'], + hidePanelActions: true, id: 'content3', render: renderFn, }, @@ -257,6 +260,7 @@ test('it should create dashboard input without the content which throws error', content3: { explicitInput: { disabledActions: ['togglePanel'], + hidePanelActions: true, id: 'content3', render: renderFn, }, diff --git a/src/plugins/content_management/public/components/section_input.ts b/src/plugins/content_management/public/components/section_input.ts index 3ae47b84881d..1404e7cd912b 100644 --- a/src/plugins/content_management/public/components/section_input.ts +++ b/src/plugins/content_management/public/components/section_input.ts @@ -31,6 +31,7 @@ export const createCardInput = ( id: section.id, title: section.title ?? '', hidePanelTitles: true, + hidePanelActions: true, viewMode: ViewMode.VIEW, columns: section.columns, wrap: section.wrap, @@ -175,6 +176,8 @@ export const createDashboardInput = async ( if (content.kind === 'custom') { panelConfig.type = CUSTOM_CONTENT_EMBEDDABLE; panelConfig.explicitInput.render = content.render; + // Currently, for custom content, there is no case that requires panel actions, so hide it + panelConfig.explicitInput.hidePanelActions = true; } panels[content.id] = panelConfig; diff --git a/src/plugins/content_management/public/components/section_render.tsx b/src/plugins/content_management/public/components/section_render.tsx index 457b07cb7822..9f7ddaf6e2f6 100644 --- a/src/plugins/content_management/public/components/section_render.tsx +++ b/src/plugins/content_management/public/components/section_render.tsx @@ -43,7 +43,7 @@ const DashboardSection = ({ section, embeddable, contents$, savedObjectsClient } // const input = createDashboardSection(section, contents ?? []); return ( // to make dashboard section align with others add margin left and right -8px -
+
); @@ -82,7 +82,7 @@ const CardSection = ({ section, embeddable, contents$ }: Props) => { ) : null} {isCardVisible && ( <> - + )} diff --git a/src/plugins/home/public/application/components/__snapshots__/home_list_card.test.tsx.snap b/src/plugins/home/public/application/components/__snapshots__/home_list_card.test.tsx.snap index 8ff4e1d85325..fdc4a20def11 100644 --- a/src/plugins/home/public/application/components/__snapshots__/home_list_card.test.tsx.snap +++ b/src/plugins/home/public/application/components/__snapshots__/home_list_card.test.tsx.snap @@ -4,7 +4,7 @@ exports[` should render static content normally 1`] = `
should render static content normally 1`] = `
-

What's New -

+
{ return ( <> - + { gutterSize="none" > - -

{config.title}

+ +

{config.title}

diff --git a/src/plugins/home/public/application/home_render.tsx b/src/plugins/home/public/application/home_render.tsx index 03babca342eb..ef73d7c44d99 100644 --- a/src/plugins/home/public/application/home_render.tsx +++ b/src/plugins/home/public/application/home_render.tsx @@ -50,7 +50,7 @@ export const setupHome = (contentManagement: ContentManagementPluginSetup) => { { id: SECTIONS.GET_STARTED, order: 1000, - title: 'Define your path forward with OpenSearch', + title: 'Get started with OpenSearch’s powerful features', kind: 'card', }, ], diff --git a/src/plugins/saved_objects_management/public/management_section/recent_work.tsx b/src/plugins/saved_objects_management/public/management_section/recent_work.tsx index 04cae46c1cea..eb04652d6343 100644 --- a/src/plugins/saved_objects_management/public/management_section/recent_work.tsx +++ b/src/plugins/saved_objects_management/public/management_section/recent_work.tsx @@ -11,7 +11,6 @@ import { EuiPanel, EuiFlexGrid, EuiFlexGroup, - EuiTitle, EuiFilterGroup, EuiFilterButton, EuiComboBox, @@ -21,6 +20,7 @@ import { EuiToolTip, EuiSpacer, EuiText, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { @@ -167,12 +167,12 @@ export const RecentWork = (props: { core: CoreStart; workspaceEnabled?: boolean - -

+ +

{i18n.translate('savedObjectsManagement.recentWorkSection.title', { defaultMessage: 'Assets', })} -

+

diff --git a/src/plugins/workspace/public/components/service_card/__snapshots__/workspace_list_card.test.tsx.snap b/src/plugins/workspace/public/components/service_card/__snapshots__/workspace_list_card.test.tsx.snap index 36a442328839..843c15a04714 100644 --- a/src/plugins/workspace/public/components/service_card/__snapshots__/workspace_list_card.test.tsx.snap +++ b/src/plugins/workspace/public/components/service_card/__snapshots__/workspace_list_card.test.tsx.snap @@ -3,7 +3,7 @@ exports[`workspace list card render normally should show workspace list card correctly 1`] = `
-

Workspaces -

+
{ } return ( - + { - -

Workspaces

+ +

Workspaces

From a9e70686b1e81e579a910b63afde632418c5aa5c Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:57:07 -0700 Subject: [PATCH 252/276] Support injecting `DataStructureMeta` from `QueryEditorExtensions` for Query Assist (#7871) (#7888) * fix query editor extensions enhance key * add query assist icons to clusters if available * allow custom icon for `DATA_STRUCTURE_META_TYPES.FEATURE` * Changeset file for PR #7871 created/updated --------- (cherry picked from commit 9bc2433a35327c790c7d624eb056b58030dbdd83) Signed-off-by: Joshua Li Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> Co-authored-by: Ashwin P Chandran --- changelogs/fragments/7871.yml | 2 + src/plugins/data/common/datasets/types.ts | 4 +- .../dataset_service/lib/index_pattern_type.ts | 5 +- .../dataset_service/lib/index_type.ts | 6 +- .../query_string/dataset_service/lib/utils.ts | 56 +++++++++++++ .../ui/dataset_selector/advanced_selector.tsx | 8 +- .../ui/dataset_selector/dataset_explorer.tsx | 20 +++-- .../query_editor_extension.tsx | 7 ++ .../query_enhancements/public/plugin.tsx | 2 +- .../query_assist/utils/create_extension.tsx | 79 +++++++++---------- 10 files changed, 129 insertions(+), 60 deletions(-) create mode 100644 changelogs/fragments/7871.yml create mode 100644 src/plugins/data/public/query/query_string/dataset_service/lib/utils.ts diff --git a/changelogs/fragments/7871.yml b/changelogs/fragments/7871.yml new file mode 100644 index 000000000000..f25eb51445d1 --- /dev/null +++ b/changelogs/fragments/7871.yml @@ -0,0 +1,2 @@ +feat: +- Support injecting `DataStructureMeta` from `QueryEditorExtensions` for Query Assist ([#7871](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7871)) \ No newline at end of file diff --git a/src/plugins/data/common/datasets/types.ts b/src/plugins/data/common/datasets/types.ts index 69549a631ab9..c98d277b7c77 100644 --- a/src/plugins/data/common/datasets/types.ts +++ b/src/plugins/data/common/datasets/types.ts @@ -139,7 +139,7 @@ export enum DATA_STRUCTURE_META_TYPES { */ export interface DataStructureFeatureMeta { type: DATA_STRUCTURE_META_TYPES.FEATURE; - icon?: string; + icon?: EuiIconProps; tooltip?: string; } @@ -157,6 +157,8 @@ export interface DataStructureDataTypeMeta { */ export interface DataStructureCustomMeta { type: DATA_STRUCTURE_META_TYPES.CUSTOM; + icon?: EuiIconProps; + tooltip?: string; [key: string]: any; } diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts index 71710adc7b50..e549a5abdf3d 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts @@ -15,6 +15,7 @@ import { } from '../../../../../common'; import { DatasetTypeConfig } from '../types'; import { getIndexPatterns } from '../../../../services'; +import { injectMetaToDataStructures } from './utils'; export const indexPatternTypeConfig: DatasetTypeConfig = { id: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, @@ -97,7 +98,7 @@ const fetchIndexPatterns = async (client: SavedObjectsClientContract): Promise { const dataSourceId = savedObject.references.find((ref) => ref.type === 'data-source')?.id; const dataSource = dataSourceId ? dataSourceMap[dataSourceId] : undefined; @@ -122,4 +123,6 @@ const fetchIndexPatterns = async (client: SavedObjectsClientContract): Promise dataStructure.parent?.id); }; diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts index 738e763c0508..6dfcdc46df49 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts @@ -8,6 +8,7 @@ import { map } from 'rxjs/operators'; import { DEFAULT_DATA, DataStructure, Dataset } from '../../../../../common'; import { DatasetTypeConfig } from '../types'; import { getSearchService, getIndexPatterns } from '../../../../services'; +import { injectMetaToDataStructures } from './utils'; const INDEX_INFO = { LOCAL_DATASOURCE: { @@ -93,14 +94,15 @@ const fetchDataSources = async (client: SavedObjectsClientContract) => { type: 'data-source', perPage: 10000, }); - const dataSources: DataStructure[] = [INDEX_INFO.LOCAL_DATASOURCE]; - return dataSources.concat( + const dataSources: DataStructure[] = [INDEX_INFO.LOCAL_DATASOURCE].concat( resp.savedObjects.map((savedObject) => ({ id: savedObject.id, title: savedObject.attributes.title, type: 'DATA_SOURCE', })) ); + + return injectMetaToDataStructures(dataSources); }; const fetchIndices = async (dataStructure: DataStructure): Promise => { diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/utils.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/utils.ts new file mode 100644 index 000000000000..aada2c2421cf --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/utils.ts @@ -0,0 +1,56 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { DataStructure, DataStructureMeta } from '../../../../../common'; +import { getQueryService } from '../../../../services'; + +/** + * Inject {@link DataStructureMeta} to DataStructures based on + * {@link QueryEditorExtensions}. + * + * This function combines the meta fields from QueryEditorExtensions and + * provided data structures. Lower extension order is higher priority, and + * existing meta fields have highest priority. + * + * @param dataStructures - {@link DataStructure} + * @param selectDataSourceId - function to get data source id given a data structure + * @returns data structures with meta + */ +export const injectMetaToDataStructures = async ( + dataStructures: DataStructure[], + selectDataSourceId: (dataStructure: DataStructure) => string | undefined = ( + dataStructure: DataStructure + ) => dataStructure.id +) => { + const queryEditorExtensions = Object.values( + getQueryService().queryString.getLanguageService().getQueryEditorExtensionMap() + ); + queryEditorExtensions.sort((a, b) => b.order - a.order); + + return Promise.all( + dataStructures.map(async (dataStructure) => { + const metaArray = await Promise.allSettled( + queryEditorExtensions.map((curr) => + curr.getDataStructureMeta?.(selectDataSourceId(dataStructure)) + ) + ).then((settledResults) => + settledResults + .filter( + (result: PromiseSettledResult): result is PromiseFulfilledResult => + result.status === 'fulfilled' + ) + .map((result) => result.value) + ); + const meta = metaArray.reduce( + (acc, curr) => (acc || curr ? ({ ...acc, ...curr } as DataStructureMeta) : undefined), + undefined + ); + if (meta || dataStructure.meta) { + dataStructure.meta = { ...meta, ...dataStructure.meta } as DataStructureMeta; + } + return dataStructure; + }) + ); +}; diff --git a/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx b/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx index a319c9a376bd..8afaedbb492e 100644 --- a/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx +++ b/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx @@ -37,11 +37,11 @@ export const AdvancedSelector = ({ .getTypes() .map((type) => { return { - id: type!.id, - title: type!.title, - type: type!.id, + id: type.id, + title: type.title, + type: type.id, meta: { - ...type!.meta, + ...type.meta, type: DATA_STRUCTURE_META_TYPES.TYPE, }, } as DataStructure; diff --git a/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx b/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx index dd35ce8065b2..48a0dcac84b2 100644 --- a/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx +++ b/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx @@ -190,26 +190,24 @@ const LoadingEmptyColumn = ({ isLoading }: { isLoading: boolean }) => ); const appendIcon = (item: DataStructure) => { - if (item.meta?.type === DATA_STRUCTURE_META_TYPES.FEATURE) { + if (item.meta?.type === DATA_STRUCTURE_META_TYPES.TYPE) { + return ( + + + + ); + } else { if (item.meta?.icon && item.meta?.tooltip) { return ( - + ); } else if (item.meta?.icon) { - return ; + return ; } } - if (item.meta?.type === DATA_STRUCTURE_META_TYPES.TYPE) { - return ( - - - - ); - } - return null; }; diff --git a/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.tsx b/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.tsx index 86d904d2b2b8..be74558fae70 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor_extensions/query_editor_extension.tsx @@ -7,6 +7,7 @@ import { EuiErrorBoundary } from '@elastic/eui'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import ReactDOM from 'react-dom'; import { Observable } from 'rxjs'; +import { DataStructureMeta } from '../../../../common'; interface QueryEditorExtensionProps { config: QueryEditorExtensionConfig; @@ -48,6 +49,12 @@ export interface QueryEditorExtensionConfig { * @returns whether the extension is enabled. */ isEnabled$: (dependencies: QueryEditorExtensionDependencies) => Observable; + /** + * @returns DataStructureMeta for a given data source id. + */ + getDataStructureMeta?: ( + dataSourceId: string | undefined + ) => Promise; /** * A function that returns the query editor extension component. The component * will be displayed on top of the query editor in the search bar. diff --git a/src/plugins/query_enhancements/public/plugin.tsx b/src/plugins/query_enhancements/public/plugin.tsx index 62f5270fa1b1..ffbd7af326f7 100644 --- a/src/plugins/query_enhancements/public/plugin.tsx +++ b/src/plugins/query_enhancements/public/plugin.tsx @@ -95,7 +95,7 @@ export class QueryEnhancementsPlugin queryString.getLanguageService().registerLanguage(sqlLanguageConfig); data.__enhance({ - ui: { + editor: { queryEditorExtension: createQueryAssistExtension(core.http, data, this.config.queryAssist), }, }); diff --git a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx index f7614547c127..bebe250a91ce 100644 --- a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx +++ b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx @@ -6,7 +6,7 @@ import { HttpSetup } from 'opensearch-dashboards/public'; import React, { useEffect, useState } from 'react'; import { distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators'; -import { DEFAULT_DATA } from '../../../../data/common'; +import { DATA_STRUCTURE_META_TYPES, DEFAULT_DATA } from '../../../../data/common'; import { DataPublicPluginSetup, QueryEditorExtensionConfig, @@ -15,16 +15,32 @@ import { import { API } from '../../../common'; import { ConfigSchema } from '../../../common/config'; import { QueryAssistBanner, QueryAssistBar } from '../components'; +import assistantMark from '../../assets/query_assist_mark.svg'; + +/** + * @returns list of query assist supported languages for the given data source. + */ +const getAvailableLanguagesForDataSource = (() => { + const availableLanguagesByDataSource: Map = new Map(); + return async (http: HttpSetup, dataSourceId: string | undefined) => { + const cached = availableLanguagesByDataSource.get(dataSourceId); + if (cached !== undefined) return cached; + const languages = await http + .get<{ configuredLanguages: string[] }>(API.QUERY_ASSIST.LANGUAGES, { + query: { dataSourceId }, + }) + .then((response) => response.configuredLanguages) + .catch(() => []); + availableLanguagesByDataSource.set(dataSourceId, languages); + return languages; + }; +})(); /** * @returns observable list of query assist agent configured languages in the * selected data source. */ -const getAvailableLanguages$ = ( - availableLanguagesByDataSource: Map, - http: HttpSetup, - data: DataPublicPluginSetup -) => +const getAvailableLanguages$ = (http: HttpSetup, data: DataPublicPluginSetup) => data.query.queryString.getUpdates$().pipe( startWith(data.query.queryString.getQuery()), distinctUntilChanged(), @@ -34,16 +50,7 @@ const getAvailableLanguages$ = ( if (query.dataset?.dataSource?.type !== DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH) return []; const dataSourceId = query.dataset?.dataSource?.id; - const cached = availableLanguagesByDataSource.get(dataSourceId); - if (cached !== undefined) return cached; - const languages = await http - .get<{ configuredLanguages: string[] }>(API.QUERY_ASSIST.LANGUAGES, { - query: { dataSourceId }, - }) - .then((response) => response.configuredLanguages) - .catch(() => []); - availableLanguagesByDataSource.set(dataSourceId, languages); - return languages; + return getAvailableLanguagesForDataSource(http, dataSourceId); }) ); @@ -52,24 +59,27 @@ export const createQueryAssistExtension = ( data: DataPublicPluginSetup, config: ConfigSchema['queryAssist'] ): QueryEditorExtensionConfig => { - const availableLanguagesByDataSource: Map = new Map(); - return { id: 'query-assist', order: 1000, + getDataStructureMeta: async (dataSourceId) => { + const isEnabled = await getAvailableLanguagesForDataSource(http, dataSourceId).then( + (languages) => languages.length > 0 + ); + if (isEnabled) { + return { + type: DATA_STRUCTURE_META_TYPES.FEATURE, + icon: { type: assistantMark }, + tooltip: 'Query assist is available', + }; + } + }, isEnabled$: () => - getAvailableLanguages$(availableLanguagesByDataSource, http, data).pipe( - map((languages) => languages.length > 0) - ), + getAvailableLanguages$(http, data).pipe(map((languages) => languages.length > 0)), getComponent: (dependencies) => { // only show the component if user is on a supported language. return ( - + ); @@ -77,13 +87,7 @@ export const createQueryAssistExtension = ( getBanner: (dependencies) => { // advertise query assist if user is not on a supported language. return ( - + conf.language)} @@ -95,7 +99,6 @@ export const createQueryAssistExtension = ( }; interface QueryAssistWrapperProps { - availableLanguagesByDataSource: Map; dependencies: QueryEditorExtensionDependencies; http: HttpSetup; data: DataPublicPluginSetup; @@ -108,11 +111,7 @@ const QueryAssistWrapper: React.FC = (props) => { useEffect(() => { let mounted = true; - const subscription = getAvailableLanguages$( - props.availableLanguagesByDataSource, - props.http, - props.data - ).subscribe((languages) => { + const subscription = getAvailableLanguages$(props.http, props.data).subscribe((languages) => { const available = languages.includes(props.dependencies.language); if (mounted) setVisible(props.invert ? !available : available); }); From abed5ba1a61e191847f0c64a22b026628445387f Mon Sep 17 00:00:00 2001 From: "Qingyang(Abby) Hu" Date: Wed, 28 Aug 2024 12:40:12 -0700 Subject: [PATCH 253/276] [Manual backport 2.x] Query editor UI changes (#7889) * query editor ui changes Signed-off-by: abbyhu2000 * remove sidebar Signed-off-by: abbyhu2000 --------- Signed-off-by: abbyhu2000 --- changelogs/fragments/7866.yml | 2 + .../language_service/_recent_query.scss | 4 + .../language_service/flyout_containers.tsx | 51 ++ .../get_query_control_links.tsx | 172 ++++++ .../language_service/language_service.ts | 4 + .../ppl_docs/commands/dedup.ts | 93 +++ .../ppl_docs/commands/eval.ts | 68 +++ .../ppl_docs/commands/fields.ts | 48 ++ .../ppl_docs/commands/head.ts | 56 ++ .../ppl_docs/commands/index.ts | 18 + .../ppl_docs/commands/parse.ts | 86 +++ .../ppl_docs/commands/rare.ts | 67 +++ .../ppl_docs/commands/rename.ts | 52 ++ .../ppl_docs/commands/search.ts | 49 ++ .../ppl_docs/commands/sort.ts | 93 +++ .../ppl_docs/commands/stats.ts | 282 +++++++++ .../ppl_docs/commands/syntax.ts | 21 + .../language_service/ppl_docs/commands/top.ts | 48 ++ .../ppl_docs/commands/where.ts | 31 + .../ppl_docs/functions/condition.ts | 162 ++++++ .../ppl_docs/functions/datetime.ts | 537 ++++++++++++++++++ .../ppl_docs/functions/full_text_search.ts | 78 +++ .../ppl_docs/functions/index.ts | 10 + .../ppl_docs/functions/math.ts | 518 +++++++++++++++++ .../ppl_docs/functions/string.ts | 215 +++++++ .../language_service/ppl_docs/groups.tsx | 126 ++++ .../ppl_docs/language_structure/datatypes.ts | 326 +++++++++++ .../language_structure/identifiers.ts | 71 +++ .../ppl_docs/language_structure/index.ts | 7 + .../language_service/ppl_docs/overview.tsx | 28 + .../language_service/ppl_reference_flyout.tsx | 101 ++++ .../language_service/recent_query.tsx | 169 ++++++ .../language_service/sql_reference_flyout.tsx | 61 ++ .../query/query_string/query_history.ts | 3 +- .../query_string/query_string_manager.ts | 4 +- .../public/ui/filter_bar/filter_options.tsx | 26 +- .../ui/query_editor/_language_selector.scss | 2 + .../public/ui/query_editor/_query_editor.scss | 6 +- .../default_editor/_default_editor.scss | 15 +- .../editors/default_editor/index.tsx | 46 +- .../public/ui/query_editor/editors/shared.tsx | 92 +-- .../public/ui/query_editor/query_editor.tsx | 51 +- .../query_editor_btn_collapse.tsx | 33 -- .../ui/query_editor/query_editor_top_row.tsx | 4 +- .../data/public/ui/search_bar/search_bar.tsx | 32 +- 45 files changed, 3828 insertions(+), 140 deletions(-) create mode 100644 changelogs/fragments/7866.yml create mode 100644 src/plugins/data/public/query/query_string/language_service/_recent_query.scss create mode 100644 src/plugins/data/public/query/query_string/language_service/flyout_containers.tsx create mode 100644 src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/dedup.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/eval.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/fields.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/head.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/index.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/parse.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/rare.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/rename.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/search.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/sort.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/stats.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/syntax.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/top.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/where.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/condition.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/datetime.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/full_text_search.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/index.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/math.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/string.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/groups.tsx create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/datatypes.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/identifiers.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/index.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_docs/overview.tsx create mode 100644 src/plugins/data/public/query/query_string/language_service/ppl_reference_flyout.tsx create mode 100644 src/plugins/data/public/query/query_string/language_service/recent_query.tsx create mode 100644 src/plugins/data/public/query/query_string/language_service/sql_reference_flyout.tsx delete mode 100644 src/plugins/data/public/ui/query_editor/query_editor_btn_collapse.tsx diff --git a/changelogs/fragments/7866.yml b/changelogs/fragments/7866.yml new file mode 100644 index 000000000000..9cc5d4863d55 --- /dev/null +++ b/changelogs/fragments/7866.yml @@ -0,0 +1,2 @@ +feat: +- Query editor UI changes ([#7866](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7866)) \ No newline at end of file diff --git a/src/plugins/data/public/query/query_string/language_service/_recent_query.scss b/src/plugins/data/public/query/query_string/language_service/_recent_query.scss new file mode 100644 index 000000000000..faac658f685f --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/_recent_query.scss @@ -0,0 +1,4 @@ +.recentQuery__table { + padding: $euiSizeXS; + width: 1320px; +} diff --git a/src/plugins/data/public/query/query_string/language_service/flyout_containers.tsx b/src/plugins/data/public/query/query_string/language_service/flyout_containers.tsx new file mode 100644 index 000000000000..4d11d2ed01d7 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/flyout_containers.tsx @@ -0,0 +1,51 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFlyout } from '@elastic/eui'; +import React from 'react'; + +/* + * "FlyoutContainers" component used to create flyouts + * + * Props taken in as params are: + * flyoutHeader - header JSX element of flyout + * flyoutBody - body JSX element of flyout + * flyoutFooter - footer JSX element of flyout + * ariaLabel - aria-label for focus of flyout + */ + +interface Props { + closeFlyout: () => void; + flyoutHeader: JSX.Element; + flyoutBody: JSX.Element; + flyoutFooter: JSX.Element; + ariaLabel: string; + size?: string; +} + +export const FlyoutContainers = ({ + closeFlyout, + flyoutHeader, + flyoutBody, + flyoutFooter, + ariaLabel, + size, +}: Props) => { + return ( +
+ closeFlyout()} + size={size ? size : 'm'} + aria-labelledby={ariaLabel} + > + {flyoutHeader} + {flyoutBody} + {flyoutFooter} + +
+ ); +}; diff --git a/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx b/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx new file mode 100644 index 000000000000..9b92d22ae432 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx @@ -0,0 +1,172 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; +import React, { useState } from 'react'; +import { + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiPopoverTitle, + EuiText, + EuiWrappingPopover, +} from '@elastic/eui'; +import ReactDOM from 'react-dom'; +import { FormattedMessage } from 'react-intl'; +import { + OpenSearchDashboardsContextProvider, + toMountPoint, +} from '../../../../../opensearch_dashboards_react/public'; +import { IDataPluginServices } from '../../../types'; +import { PPLReferenceFlyout } from './ppl_reference_flyout'; + +export interface QueryControl { + id: string; + label: string; + testId: string; + ariaLabel: string; + run: (anchorElement: HTMLElement) => void; + iconType: string; +} + +export const QueryControls = (props: { + services: IDataPluginServices; + queryLanguage: string; + onToggleCollapse: () => void; + savedQueryManagement?: any; + additionalControls?: QueryControl[]; +}) => { + const [isCollapsed, setIsCollapsed] = useState(false); + const [isLanguageReferenceOpen, setIsLanguageReferenceOpen] = useState(false); + + const languageReferenceContainer = document.createElement('div'); + + const onCloseLanguageReference = () => { + ReactDOM.unmountComponentAtNode(languageReferenceContainer); + setIsLanguageReferenceOpen(false); + }; + + const osdDQLDocs = 'https://opensearch.org/docs/2.16/dashboards/dql)'; + const dqlFullName = ( + + ); + + const languageReference: QueryControl = { + id: 'languageReference', + label: i18n.translate('discover.queryControls.languageReference', { + defaultMessage: 'Open', + }), + testId: 'languageReference', + ariaLabel: i18n.translate('discover.queryControls.languageReference', { + defaultMessage: `Language Reference`, + }), + run: async (anchorElement) => { + if (props.queryLanguage === 'PPL' || props.queryLanguage === 'SQL') { + const flyoutSession = props.services.overlays!.openFlyout( + toMountPoint( + + flyoutSession?.close?.().then()} + makeUrl={(searchId: any) => `#/view/${encodeURIComponent(searchId)}`} + /> + + ) + ); + } else { + if (isLanguageReferenceOpen) { + onCloseLanguageReference(); + return; + } + + setIsLanguageReferenceOpen(true); + document.body.appendChild(languageReferenceContainer); + + const element = ( + + + + +
+ +

+ + {dqlFullName} + + ), + }} + /> +

+
+
+
+ ); + + ReactDOM.render(element, languageReferenceContainer); + } + }, + iconType: 'iInCircle', + }; + + const languageToggle: QueryControl = { + id: 'languageToggle', + label: i18n.translate('discover.queryControls.languageToggle', { + defaultMessage: 'Toggle', + }), + testId: 'languageToggle', + ariaLabel: i18n.translate('discover.queryControls.languageToggle', { + defaultMessage: `Language Toggle`, + }), + run: () => { + setIsCollapsed(!isCollapsed); + props.onToggleCollapse(); + }, + iconType: isCollapsed ? 'expand' : 'minimize', + }; + + const queryControls = + props.queryLanguage === 'PPL' || props.queryLanguage === 'SQL' + ? [languageReference, languageToggle] + : [languageReference]; + + if (props.additionalControls) { + queryControls.push(...props.additionalControls); + } + + return ( + + {queryControls.map((queryControl) => ( + + queryControl.run(event.currentTarget)} + /> + + ))} + {props.savedQueryManagement} + + ); +}; diff --git a/src/plugins/data/public/query/query_string/language_service/language_service.ts b/src/plugins/data/public/query/query_string/language_service/language_service.ts index 328912a78666..923838c26bb2 100644 --- a/src/plugins/data/public/query/query_string/language_service/language_service.ts +++ b/src/plugins/data/public/query/query_string/language_service/language_service.ts @@ -27,6 +27,10 @@ export class LanguageService { this.queryEditorExtensionMap = {}; } + public createDefaultQueryEditor() { + return createEditor(SingleLineInput, SingleLineInput, DQLBody); + } + public __enhance = (enhancements: UiEnhancements) => { if (enhancements.queryEditorExtension) { this.queryEditorExtensionMap[enhancements.queryEditorExtension.id] = diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/dedup.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/dedup.ts new file mode 100644 index 000000000000..1acde2fb90c9 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/dedup.ts @@ -0,0 +1,93 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const dedupCmd = `## dedup +--- + +### Description + +Use the \'dedup\' command to remove identical documents from the search results, based on the specified field. + +### Syntax + +dedup \[int\] <field-list> \[keepempty=<bool>\] +\[consecutive=<bool>\] + +- \`field-list\`: Required. The comma-delimited field list. At least one field is required. +- \`consecutive\`: Optional. If set to \`true\`, removes duplicate events, where the duplicate events have consecutive timestamps. Default is \`false\`. +- \`int\`: Optional. The \'dedup\' command retains multiple events for each combination when you specify \`<int>\`. The number for \`<int>\` must be greater than 0. If you do not specify a number, only the first occurring event is kept. All other duplicates are removed from the results. Default is \`1\`. +- \`keepempty\`: Optional. If set to \`true\`, keeps the document if any field in the \`field-list\` is null or missing. Default is \`false\`. + +#### Example 1: Dedup by one field + +The following example PPL query shows how to use \`dedup\` to remove duplicate documents based on the \`gender\` field: + + os> source=accounts | dedup gender | fields account_number, gender; + fetched rows / total rows = 2/2 + +------------------+----------+ + | account_number | gender | + |------------------+----------| + | 1 | M | + | 13 | F | + +------------------+----------+ + +#### Example 2: Keep two duplicate documents + +The following example PPL query shows how to use \`dedup\` to remove duplicate documents based on the \`gender\` field while keeping two duplicates: + + os> source=accounts | dedup 2 gender | fields account_number, gender; + fetched rows / total rows = 3/3 + +------------------+----------+ + | account_number | gender | + |------------------+----------| + | 1 | M | + | 6 | M | + | 13 | F | + +------------------+----------+ + +#### Example 3: Keep or ignore empty fields by default + +The following example PPL query shows how to use \`dedup\` to remove duplicate documents while keeping documents with null values in the specified field: + + os> source=accounts | dedup email keepempty=true | fields account_number, email; + fetched rows / total rows = 4/4 + +------------------+-----------------------+ + | account_number | email | + |------------------+-----------------------| + | 1 | amberduke@pyrami.com | + | 6 | hattiebond@netagy.com | + | 13 | null | + | 18 | daleadams@boink.com | + +------------------+-----------------------+ + +The following example PPL query shows how to use \`dedup\` to remove duplicate documents while ignoring documents with empty values in the specified field: + + os> source=accounts | dedup email | fields account_number, email; + fetched rows / total rows = 3/3 + +------------------+-----------------------+ + | account_number | email | + |------------------+-----------------------| + | 1 | amberduke@pyrami.com | + | 6 | hattiebond@netagy.com | + | 18 | daleadams@boink.com | + +------------------+-----------------------+ + +#### Example 4: Remove duplicate consecutive documents + +The following example PPL query shows how to use \`dedup\` to remove duplicate consecutive documents: + + os> source=accounts | dedup gender consecutive=true | fields account_number, gender; + fetched rows / total rows = 3/3 + +------------------+----------+ + | account_number | gender | + |------------------+----------| + | 1 | M | + | 13 | F | + | 18 | M | + +------------------+----------+ + +### Limitation +The \`dedup\` command is not rewritten to [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/). It is only run on the coordinating node. +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/eval.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/eval.ts new file mode 100644 index 000000000000..f20a5ee35198 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/eval.ts @@ -0,0 +1,68 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const evalCmd = `## eval +--- + +### Description + +Use the \'eval\' command to evaluate the expression and append the result to the search result. + +### Syntax + +eval <field>=<expression> \["," +<field>=<expression> \]... + +- \`field\`: Required. If the field name does not exist, a new field is created. If the field name exists, the value of the existing field is replaced. +- \`expression\`: Required. Any expression that is supported by the system. + +#### Example 1: Create new fields + +The following example PPL query shows how to use \`eval\` to create a new field for each document. In this example, the new field is \`doubleAge\`. + + os> source=accounts | eval doubleAge = age * 2 | fields age, doubleAge; + fetched rows / total rows = 4/4 + +-------+-------------+ + | age | doubleAge | + |-------+-------------| + | 32 | 64 | + | 36 | 72 | + | 28 | 56 | + | 33 | 66 | + +-------+-------------+ + +#### Example 2: Override existing fields + +The following example PPL query shows how to use \`eval\` to override an existing field. In this example, the existing field \`age\` is overridden by the \`age\` field plus 1. + + os> source=accounts | eval age = age + 1 | fields age; + fetched rows / total rows = 4/4 + +-------+ + | age | + |-------| + | 33 | + | 37 | + | 29 | + | 34 | + +-------+ + +#### Example 3: Create new fields based on the fields defined in the \`eval\` expression + +The following example PPL query shows how to use \`eval\` to create a new field based on the fields defined in the \`eval\` expression. In this example, the new field \`ddAge\` is the evaluation result of the \`doubleAge\` field multiplied by 2. \`doubleAge\` is defined in the \`eval\` command. + + os> source=accounts | eval doubleAge = age * 2, ddAge = doubleAge * 2 | fields age, doubleAge, ddAge; + fetched rows / total rows = 4/4 + +-------+-------------+---------+ + | age | doubleAge | ddAge | + |-------+-------------+---------| + | 32 | 64 | 128 | + | 36 | 72 | 144 | + | 28 | 56 | 112 | + | 33 | 66 | 132 | + +-------+-------------+---------+ + +### Limitation +The \`eval\` command is not rewritten to [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/). It is only run on the coordinating node. +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/fields.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/fields.ts new file mode 100644 index 000000000000..2110349b54eb --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/fields.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const fieldsCmd = `## fields +--- +### Description + +Use the \`fields\` command to specify the fields that should be included in or excluded from the search results. + +### Syntax + +fields \[+\|-\] <field-list> + +- \`field-list\`: Required. Comma-separated list of fields to keep or remove. +- \`index\`: Optional. If the plus sign \`+\` is used, only the fields specified in the field list will be included. If the minus \`-\` is used, all the fields specified in the field list will be excluded. Default is \`+\`. + +#### Example 1: Select specified fields from the search result + +The following example PPL query shows how to retrieve the \`account\_number\`, \`firstname\`, and \`lastname\` fields from the search results: + + os> source=accounts | fields account_number, firstname, lastname; + fetched rows / total rows = 4/4 + +------------------+-------------+------------+ + | account_number | firstname | lastname | + |------------------+-------------+------------| + | 1 | Amber | Duke | + | 6 | Hattie | Bond | + | 13 | Nanette | Bates | + | 18 | Dale | Adams | + +------------------+-------------+------------+ + +#### Example 2: Remove specified fields from the search results + +The following example PPL query shows how to remove the \`account\_number\` field from the search results: + + os> source=accounts | fields account_number, firstname, lastname | fields - account_number; + fetched rows / total rows = 4/4 + +-------------+------------+ + | firstname | lastname | + |-------------+------------| + | Amber | Duke | + | Hattie | Bond | + | Nanette | Bates | + | Dale | Adams | + +-------------+------------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/head.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/head.ts new file mode 100644 index 000000000000..468da72d3871 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/head.ts @@ -0,0 +1,56 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const headCmd = `## head +--- + +### Description + +Use the \`head\` command to return the first N number of lines from a search result. + +### Syntax + +head \[N\] + +- \`N\`: Optional. The number of results you want to return. Default is 10. + +#### Example 1: Get the first 10 results + +The following example PPL query shows how to use \`head\` to return the first 10 search results: + + os> source=accounts | fields firstname, age | head; + fetched rows / total rows = 10/10 + +---------------+-----------+ + | firstname | age | + |---------------+-----------| + | Amber | 32 | + | Hattie | 36 | + | Nanette | 28 | + | Dale | 33 | + | Elinor | 36 | + | Virginia | 39 | + | Dillard | 34 | + | Mcgee | 39 | + | Aurelia | 37 | + | Fulton | 23 | + +---------------+-----------+ + +#### Example 2: Get the first N results + +The following example PPL query shows how to use \`head\` to get a specified number of search results. In this example, N is equal to 3: + + os> source=accounts | fields firstname, age | head 3; + fetched rows / total rows = 3/3 + +---------------+-----------+ + | firstname | age | + |---------------+-----------| + | Amber | 32 | + | Hattie | 36 | + | Nanette | 28 | + +---------------+-----------+ + +#### Limitation +The \`head\` command is not rewritten to [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/). It is only run on the coordinating node. +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/index.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/index.ts new file mode 100644 index 000000000000..27328a4c2be8 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { dedupCmd } from './dedup'; +export { evalCmd } from './eval'; +export { fieldsCmd } from './fields'; +export { headCmd } from './head'; +export { parseCmd } from './parse'; +export { rareCmd } from './rare'; +export { renameCmd } from './rename'; +export { searchCmd } from './search'; +export { sortCmd } from './sort'; +export { statsCmd } from './stats'; +export { syntaxCmd } from './syntax'; +export { topCmd } from './top'; +export { whereCmd } from './where'; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/parse.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/parse.ts new file mode 100644 index 000000000000..28501cf8555e --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/parse.ts @@ -0,0 +1,86 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const parseCmd = `## parse +--- +### Description + +Use the \`parse\` command to extract information from a text field using a regular expression and add it to the search result. + +### Syntax + +parse <field> <regular-expression> + +- \`field\`: Required. Must be a text field. +- \`regular-expression\`: Required. The regular expression used to extract new fields from a text field. It replaces the original field if a new field name exists. + +### Regular expression + +Use the Java regular expression engine to match the entire text field of each document. Each named capture group in the expression will be converted to a new \`string\` field. + +#### Example 1: Create a new field + +The following example PPL query shows how to create new field \`host\` for each document. \`host\` becomes the hostname after the @ symbol in the \`email\` field. Parsing a null field returns an empty string. + + os> source=accounts | parse email '.+@(?.+)' | fields email, host; + fetched rows / total rows = 4/4 + +-----------------------+------------+ + | email | host | + |-----------------------+------------| + | amberduke@pyrami.com | pyrami.com | + | hattiebond@netagy.com | netagy.com | + | null | | + | daleadams@boink.com | boink.com | + +-----------------------+------------+ + +#### Example 2: Override an existing field + +The following example PPL query shows how to override the existing \`address\` field while excluding the street number: + + os> source=accounts | parse address '\\d+ (?
.+)' | fields address; + fetched rows / total rows = 4/4 + +------------------+ + | address | + |------------------| + | Holmes Lane | + | Bristol Street | + | Madison Street | + | Hutchinson Court | + +------------------+ + +#### Example 3: Filter and sort by casted-parsed field + +The following example PPL query shows how to sort street numbers that are greater than 500 in the \`address\` field: + + os> source=accounts | parse address '(?\d+) (?.+)' | where cast(streetNumber as int) > 500 | sort num(streetNumber) | fields streetNumber, street; + fetched rows / total rows = 3/3 + +----------------+----------------+ + | streetNumber | street | + |----------------+----------------| + | 671 | Bristol Street | + | 789 | Madison Street | + | 880 | Holmes Lane | + +----------------+----------------+ + +### Limitation + +The following limitations apply: + +- Parsed fields cannot be parsed again. For example, the following command is not valid: + + source=accounts | parse address '\\d+ (?.+)' | parse street '\\w+ (?\\w+)'; + +- Other commands cannot overwrite fields created by parsing. For example, in the following query, \`where\` does not match any documents because \`street\` cannot be overridden: + + source=accounts | parse address '\\d+ (?.+)' | eval street='1' | where street='1'; + +- The text field that is parsed cannot be overridden. For example, in the following query, \`street\` is not successfully parsed because \`address\` is overridden: + + source=accounts | parse address '\\d+ (?.+)' | eval address='1'; + +- Fields created by parsing cannot be filtered or sorted after using them in the \`stats\` command. For example, in the following query, \`where\` is not valid: + + source=accounts | parse email '.+@(?.+)' | stats avg(age) by host | where host=pyrami.com; +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/rare.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/rare.ts new file mode 100644 index 000000000000..61f5016f4e9e --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/rare.ts @@ -0,0 +1,67 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const rareCmd = `## rare +--- + +### Description + +Use the \`rare\` command to find the least common tuple of values across all fields in the \`field-list\` field. A maximum of 10 results is returned for each distinct tuple of group-by field values. + +### Syntax + +rare <field-list> \[by-clause\] + +- \`field-list\`: Required. A comma-separated list of field names. +- \`by-clause\`: Optional. One or more fields to group by. + +#### Example 1: Find a field's least common values + +The following example PPL query shows how to find a least common value in the \`gender\` field: + + os> source=accounts | rare gender; + fetched rows / total rows = 2/2 + +------------+ + | gender | + |------------| + | F | + |------------| + | M | + +------------+ + +#### Example 2: Find least common values in group-by fields + +The following example PPL query shows how to find a least common value in the \`age\` field that is grouped by \`gender\`: + + os> source=accounts | rare age by gender; + fetched rows / total rows = 20/20 + +----------+----------+ + | gender | age | + |----------+----------| + | F | 29 | + | F | 20 | + | F | 23 | + | F | 25 | + | F | 37 | + | F | 38 | + | F | 40 | + | F | 27 | + | F | 36 | + | F | 24 | + | M | 27 | + | M | 24 | + | M | 34 | + | M | 38 | + | M | 28 | + | M | 39 | + | M | 21 | + | M | 30 | + | M | 25 | + | M | 29 | + +----------+----------+ + +#### Limitation +The \`rare\` command is not rewritten to [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/). It is only run on the coordinating node. +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/rename.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/rename.ts new file mode 100644 index 000000000000..22d9790514a8 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/rename.ts @@ -0,0 +1,52 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const renameCmd = `## rename +--- +### Description + +Use the \`rename\` command to rename one or more fields in the search result. + +### Syntax + +rename <source-field> AS <target-field>\["," +<source-field> AS <target-field>\]... + +- \`source-field\`: Required. The field to rename. +- \`target-field\`: Required. The new field. + +#### Example 1: Rename one field + +The following example PPL query renames a field: + + os> source=accounts | rename account_number as an | fields an; + fetched rows / total rows = 4/4 + +------+ + | an | + |------| + | 1 | + | 6 | + | 13 | + | 18 | + +------+ + +#### Example 2: Rename two or more fields + +The following example PPL query renames two or more fields: + + os> source=accounts | rename account_number as an, employer as emp | fields an, emp; + fetched rows / total rows = 4/4 + +------+---------+ + | an | emp | + |------+---------| + | 1 | Pyrami | + | 6 | Netagy | + | 13 | Quility | + | 18 | null | + +------+---------+ + +#### Limitation +The \`rename\` command is not rewritten to [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/). It is only run on the coordinating node. +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/search.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/search.ts new file mode 100644 index 000000000000..2c2e361dd958 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/search.ts @@ -0,0 +1,49 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const searchCmd = `## search +--- + +### Description + +Use the \`search\` command to retrieve a document from the index. The \`search\` +command can only be used as the first command in a PPL query. + +### Syntax + +search source=<index> \[boolean-expression\] + +- \`search\`: Search keywords, which can be ignored. +- \`index\`: Required. Search commands must specify the index to query. +- \`bool-expression\`: Optional. Any expression that can be evaluated to a Boolean value. + +#### Example 1: Fetch all data from an index + +The following example PPL query shows how to fetch all documents from the \`accounts\` index: + + os> source=accounts; + fetched rows / total rows = 4/4 + +----------------+-----------+----------------------+---------+--------+--------+----------+-------+-----+-----------------------+----------+ + | account_number | firstname | address | balance | gender | city | employer | state | age | email | lastname | + +----------------+-----------+----------------------+---------+--------+--------+----------+-------+-----+-----------------------+----------+ + | 1 | Amber | 880 Holmes Lane | 39225 | M | Brogan | Pyrami | IL | 32 | amberduke@pyrami.com | Duke | + | 6 | Hattie | 671 Bristol Street | 5686 | M | Dante | Netagy | TN | 36 | hattiebond@netagy.com | Bond | + | 13 | Nanette | 789 Madison Street | 32838 | F | Nogal | Quility | VA | 28 | null | Bates | + | 18 | Dale | 467 Hutchinson Court | 4180 | M | Orick | null | MD | 33 | daleadams@boink.com | Adams | + +----------------+-----------+----------------------+---------+--------+--------+----------+-------+-----+-----------------------+----------+ + +#### Example 2: Fetch data with a condition + +The following example PPL query shows how to fetch all documents from the \`accounts\` index by using the \`or\` condition. + + os> source=accounts account_number=1 or gender="F"; + fetched rows / total rows = 2/2 + +------------------+-------------+--------------------+-----------+----------+--------+------------+---------+-------+----------------------+------------+ + | account_number | firstname | address | balance | gender | city | employer | state | age | email | lastname | + |------------------+-------------+--------------------+-----------+----------+--------+------------+---------+-------+----------------------+------------| + | 1 | Amber | 880 Holmes Lane | 39225 | M | Brogan | Pyrami | IL | 32 | amberduke@pyrami.com | Duke | + | 13 | Nanette | 789 Madison Street | 32838 | F | Nogal | Quility | VA | 28 | null | Bates | + +------------------+-------------+--------------------+-----------+----------+--------+------------+---------+-------+----------------------+------------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/sort.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/sort.ts new file mode 100644 index 000000000000..d31e84a96e29 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/sort.ts @@ -0,0 +1,93 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const sortCmd = `## sort +--- +### Description + +Use the \`sort\` command to sort search results by a specified field. + +### Syntax + +sort <\[+\|-\] sort-field>... + +- \`sort-field\`: Required. The field to sort by. +- \[+\|-\]: Optional. The symbols used to indicate the sorting order. A plus sign \[+\] indicates ascending order, with null and missing values first. A minus sign \[-\] indicates descending order, with null and missing last. Default is \[+\], with null and missing first. + +#### Example 1: Sort by one field + +The following example PPL query shows how to sort documents by one field in ascending order: + + os> source=accounts | sort age | fields account_number, age; + fetched rows / total rows = 4/4 + +------------------+-------+ + | account_number | age | + |------------------+-------| + | 13 | 28 | + | 1 | 32 | + | 18 | 33 | + | 6 | 36 | + +------------------+-------+ + +#### Example 2: Sort by one field and return all results + +The following example PPL query shows how to sort by one field and return all results in ascending order: + + os> source=accounts | sort age | fields account_number, age; + fetched rows / total rows = 4/4 + +------------------+-------+ + | account_number | age | + |------------------+-------| + | 13 | 28 | + | 1 | 32 | + | 18 | 33 | + | 6 | 36 | + +------------------+-------+ + +#### Example 3: Sort by one field in descending order + +The following example PPL query shows how to sort by one field in descending order: + + os> source=accounts | sort - age | fields account_number, age; + fetched rows / total rows = 4/4 + +------------------+-------+ + | account_number | age | + |------------------+-------| + | 6 | 36 | + | 18 | 33 | + | 1 | 32 | + | 13 | 28 | + +------------------+-------+ + +#### Example 4: Sort multiple fields in both ascending and descending order + +The following example PPL query shows how to sort by multiple fields in both ascending and descending order. In this example, the \`gender\` field is in ascending order and the \`age\` field is in descending order. + + os> source=accounts | sort + gender, - age | fields account_number, gender, age; + fetched rows / total rows = 4/4 + +------------------+----------+-------+ + | account_number | gender | age | + |------------------+----------+-------| + | 13 | F | 28 | + | 6 | M | 36 | + | 18 | M | 33 | + | 1 | M | 32 | + +------------------+----------+-------+ + +#### Example 5: Sort by field, including null values + +The following example PPL query shows how to sort by the \`employer\` field using the default order (\[+\] with null and missing first): + + os> source=accounts | sort employer | fields employer; + fetched rows / total rows = 4/4 + +------------+ + | employer | + |------------| + | null | + | Netagy | + | Pyrami | + | Quility | + +------------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/stats.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/stats.ts new file mode 100644 index 000000000000..5392c9ef4b5d --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/stats.ts @@ -0,0 +1,282 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const statsCmd = `## stats +--- + +### Description + +Use the \`stats\` command to calculate the aggregation from the search results. + +The following table catalogs the aggregation functions and defines how the null and missing values are handled. + +| | | | +|----------|-------------|-------------| +| Function | NULL | MISSING | +| COUNT | Not counted | Not counted | +| SUM | Ignore | Ignore | +| AVG | Ignore | Ignore | +| MAX | Ignore | Ignore | +| MIN | Ignore | Ignore | + +### Syntax + +stats <aggregation>... \[by-clause\]... + +- \`aggregation\`: Required. The aggregation function that must be applied to the field. +- \`by-clause\`: Optional. One or more fields to group by. Default: If \`<by-clause>\` is not specified, the \`stats\` command returns one row, which is the aggregation for the entire result set. + +### Aggregation functions +--- +#### COUNT + +The \`count\` function returns the number of rows in the result set. The following is an example PPL query: + + os> source=accounts | stats count(); + fetched rows / total rows = 1/1 + +-----------+ + | count() | + |-----------| + | 4 | + +-----------+ + +#### SUM + +The \`SUM(expr)\` function returns the sum of the values in the expression \`expr\`. The following is an example PPL query: + + os> source=accounts | stats sum(age) by gender; + fetched rows / total rows = 2/2 + +------------+----------+ + | sum(age) | gender | + |------------+----------| + | 28 | F | + | 101 | M | + +------------+----------+ + +#### AVG + +The \`AVG(expr)\` function returns the average of the values in the expression \`expr\`. The following is an example PPL query: + + os> source=accounts | stats avg(age) by gender; + fetched rows / total rows = 2/2 + +--------------------+----------+ + | avg(age) | gender | + |--------------------+----------| + | 28.0 | F | + | 33.666666666666664 | M | + +--------------------+----------+ + +#### MAX + +The \`MAX(expr)\` function returns the largest value in the expression \`expr\`. The following is an example PPL query: + + os> source=accounts | stats max(age); + fetched rows / total rows = 1/1 + +------------+ + | max(age) | + |------------| + | 36 | + +------------+ + +#### MIN + +The \`MIN(expr)\` function returns the smallest value in the expression \`expr\`. The following is an example PPL query: + + os> source=accounts | stats min(age); + fetched rows / total rows = 1/1 + +------------+ + | min(age) | + |------------| + | 28 | + +------------+ + +#### VAR\_SAMP + +The \`VAR\_SAMP(expr)\` function returns the sample variance of a selection of data in the expression \`expr\`. The following is an example PPL query: + + os> source=accounts | stats var_samp(age); + fetched rows / total rows = 1/1 + +--------------------+ + | var_samp(age) | + |--------------------| + | 10.916666666666666 | + +--------------------+ + +#### VAR\_POP + +The \`VAR\_POP(expr)\` function returns the population variance of a selection of data in the expression \`expr\`. See the following example. + + os> source=accounts | stats var_pop(age); + fetched rows / total rows = 1/1 + +----------------+ + | var_pop(age) | + |----------------| + | 8.1875 | + +----------------+ + +#### STDDEV\_SAMP + +The \`STDDEV\_SAMP(expr)\` function returns the sample standard deviation of a set of values in the expression \`expr\`. The following is an example PPL query: + + os> source=accounts | stats stddev_samp(age); + fetched rows / total rows = 1/1 + +--------------------+ + | stddev_samp(age) | + |--------------------| + | 3.304037933599835 | + +--------------------+ + +#### STDDEV\_POP + +The \`STDDEV\_POP(expr)\` function returns the population standard deviation of a set of values in the expression \`expr\`. The following is an example PPL query: + + os> source=accounts | stats stddev_pop(age); + fetched rows / total rows = 1/1 + +--------------------+ + | stddev_pop(age) | + |--------------------| + | 2.8613807855648994 | + +--------------------+ + +### By clause + +The \`by\` clause can contain fields, expressions, scalar functions, or aggregation functions. The \`span\` clause can be used in the \`by\` clause to split specific fields into buckets of the same interval. The \`stats\` command then performs the aggregation on these buckets. + +The span syntax is \`span(field_expr, interval_expr)\`. By default, the interval expression in the \`span\` clause is interpreted in natural units. If the field is a date and time type field and the interval is in date and time units, you must specify the unit in the interval expression. For example, to split the \`age\` field into buckets of 10 years, you would use \`span(age, 10y). To split a timestamp field into hourly intervals, you would use \`span(timestamp, 1h)\`. + +The following table lists the available time units. + +| Span Interval Units | +|----------------------------| +| millisecond (ms) | +| second (s) | +| minute (m, case sensitive) | +| hour (h) | +| day (d) | +| week (w) | +| month (M, case sensitive) | +| quarter (q) | +| year (y) | + +### PPL queries using the stats command + +The following example PPL queries show ways you can use the \`stats\` command in your queries. + +#### Example 1: Calculate event counts + +The following example PPL query calculates event counts: + + os> source=accounts | stats count(); + fetched rows / total rows = 1/1 + +-----------+ + | count() | + |-----------| + | 4 | + +-----------+ + +#### Example 2: Calculate a field's average + +The following example PPL query calculates the average age: + + os> source=accounts | stats avg(age); + fetched rows / total rows = 1/1 + +------------+ + | avg(age) | + |------------| + | 32.25 | + +------------+ + +#### Example 3: Calculate the average of a field by group + +The following example PPL query calculates the average age grouped by gender: + + os> source=accounts | stats avg(age) by gender; + fetched rows / total rows = 2/2 + +--------------------+----------+ + | avg(age) | gender | + |--------------------+----------| + | 28.0 | F | + | 33.666666666666664 | M | + +--------------------+----------+ + +#### Example 4: Calculate the average, sum, and count of a field by group + +The following example PPL query calculates the average age, sum age, and count of events by gender. + + os> source=accounts | stats avg(age), sum(age), count() grouped by gender; + fetched rows / total rows = 2/2 + +--------------------+------------+-----------+----------+ + | avg(age) | sum(age) | count() | gender | + |--------------------+------------+-----------+----------| + | 28.0 | 28 | 1 | F | + | 33.666666666666664 | 101 | 3 | M | + +--------------------+------------+-----------+----------+ + +#### Example 5: Calculate a field's maximum + +The following example PPL query calculates the maximum age: + + os> source=accounts | stats max(age); + fetched rows / total rows = 1/1 + +------------+ + | max(age) | + |------------| + | 36 | + +------------+ + +#### Example 6: Calculate a field's min/max by group + +The following example PPL query calculates the min/max age grouped by gender: + + os> source=accounts | stats max(age), min(age) by gender; + fetched rows / total rows = 2/2 + +------------+------------+----------+ + | max(age) | min(age) | gender | + |------------+------------+----------| + | 28 | 28 | F | + | 36 | 32 | M | + +------------+------------+----------+ + +#### Example 7: Calculate a field's distinct count + +To count the number of distinct values in a field, you can use the \`DISTINCT_COUNT\` or \`DC\` function instead of the \`COUNT\` funtion. + +The following PPL query calculates both the count and distinct count of the \`gender\` field for all accounts. + + os> source=accounts | stats count(gender), distinct_count(gender); + fetched rows / total rows = 1/1 + +-----------------+--------------------------+ + | count(gender) | distinct_count(gender) | + |-----------------+--------------------------| + | 4 | 2 | + +-----------------+--------------------------+ + +#### Example 8: Calculate count by span + +The following PPL query calculates age by span of 10 years. + + os> source=accounts | stats count(age) by span(age, 10) as age_span + fetched rows / total rows = 2/2 + +--------------+------------+ + | count(age) | age_span | + |--------------+------------| + | 1 | 20 | + | 3 | 30 | + +--------------+------------+ + +#### Example 9: Calculate count by gender and span + +The following PPL query calculates age by span of 10 years and groups by gender. + + os> source=accounts | stats count() as cnt by span(age, 5) as age_span, gender + fetched rows / total rows = 3/3 + +-------+------------+----------+ + | cnt | age_span | gender | + |-------+------------+----------| + | 1 | 25 | F | + | 2 | 30 | M | + | 1 | 35 | M | + +-------+------------+----------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/syntax.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/syntax.ts new file mode 100644 index 000000000000..a37cf8be65ce --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/syntax.ts @@ -0,0 +1,21 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const syntaxCmd = `## Syntax +--- +### Command order + +The PPL query starts with a \`search\` command to reference a table to search. +Commands can be in any order. For example, in the following query, the \`search\` command references the \`accounts\` index as the source and then uses fields and a \`where\` command to perform further processing. + +\`\`\` +search source=accounts +| where age > 18 +| fields firstname, lastname +\`\`\` + +### Required and optional arguments + +Required arguments are enclosed in angle brackets \< \>, and optional arguments are enclosed in square brackets \[ \].`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/top.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/top.ts new file mode 100644 index 000000000000..0cf6b7c8b8de --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/top.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const topCmd = `## top +--- +### Description + +Use the \`top\` command to find the most common tuple of values for all +fields in the field list. + +### Syntax + +top \[N\] <field-list> \[by-clause\] + +- \`N\`: The number of results you want to return. Default is 10. +- \`field-list\`: Required. The comma-delimited field list. +- \`by-clause\`: Optional. One or more fields to group by. + +#### Example 1: Find the most common values in a field + +The following example PPL query finds the most common gender. + + os> source=accounts | top 1 gender; + fetched rows / total rows = 1/1 + +------------+ + | gender | + |------------| + | M | + +------------+ + +#### Example 2: Find the most common values grouped by gender + +The following example PPL query finds the most common age grouped by gender. + + os> source=accounts | top 1 age by gender; + fetched rows / total rows = 2/2 + +----------+----------+ + | gender | age | + |----------+----------| + | F | 39 | + | M | 31 | + +----------+----------+ + +#### Limitation +The \`top\` command is not rewritten to [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/). It is only run on the coordinating node. +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/where.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/where.ts new file mode 100644 index 000000000000..b92d65b01312 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/commands/where.ts @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const whereCmd = `## where +--- + +### Description + +Use the \`where\` command to filter search results. The \`where\` command only returns the result when the \`bool-expression\` is set to \`true\`. + +### Syntax + +\`where <boolean-expression>\` + +- \`bool-expression\`: Optional. Any expression that can be evaluated to a Boolean expression. + +#### Example 1: Filter the result set with a condition + +The following example PPL query fetches all documents from the \`accounts\` index using an \`or\ condition. + + os> source=accounts | where account_number=1 or gender="F" | fields account_number, gender; + fetched rows / total rows = 2/2 + +------------------+----------+ + | account_number | gender | + |------------------+----------| + | 1 | M | + | 13 | F | + +------------------+----------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/condition.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/condition.ts new file mode 100644 index 000000000000..4824b5aa2300 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/condition.ts @@ -0,0 +1,162 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const conditionFunction = `## Condition +--- + +### Condition functions + +PPL functions use the search capabilities of the OpenSearch engine. However, these functions don't execute directly within the OpenSearch plugin's memory. Instead, they facilitate the global filtering of query results based on specific conditions, such as a \`WHERE\` or \`HAVING\` clause. + +The following sections describe the condition PPL functions. + +### ISNULL + +The \`isnull(field)\` function checks a specific field and returns \`true\` if the field contains no data, that is, it's null. + +**Argument type:** All supported data types + +**Return type:** \`BOOLEAN\` + +#### Example + + os> source=accounts | eval result = isnull(employer) | fields result, employer, firstname + fetched rows / total rows = 4/4 + +----------+------------+-------------+ + | result | employer | firstname | + |----------+------------+-------------| + | False | Pyrami | Amber | + | False | Netagy | Hattie | + | False | Quility | Nanette | + | True | null | Dale | + +----------+------------+-------------+ + +### ISNOTNULL + +The \`isnotnull(field)\` function is the opposite of \`isnull(field)\`. Instead of checking for null values, it checks a specific field and returns \`true\` if the field contains data, that is, it is not null. + +**Argument type:** All supported data types + +**Return type:** \`BOOLEAN\` + +#### Example + + os> source=accounts | where not isnotnull(employer) | fields account_number, employer + fetched rows / total rows = 1/1 + +------------------+------------+ + | account_number | employer | + |------------------+------------| + | 18 | null | + +------------------+------------+ + +### EXISTS + +OpenSearch does not differentiate between null and missing. Thus, a function such as \`ismissing\` or \`isnotmissing\` cannot be used to test if a field exists or not. The \`isnull\` or \`isnotnull\` functions can be used for this purpose. + +#### Example + + os> source=accounts | where isnull(email) | fields account_number, email + fetched rows / total rows = 1/1 + +------------------+---------+ + | account_number | email | + |------------------+---------| + | 13 | null | + +------------------+---------+ + +### IFNULL + +The \`ifnull(field1, field2)\` function returns the value in the first field if it is not null; otherwise, it returns the value in the second field. + +**Argument type:** All supported data types (Note that the semantic check will fail if the parameters are different types.) + +**Return type:** Any + +#### Example + + os> source=accounts | eval result = ifnull(employer, 'default') | fields result, employer, firstname + fetched rows / total rows = 4/4 + +----------+------------+-------------+ + | result | employer | firstname | + |----------+------------+-------------| + | Pyrami | Pyrami | Amber | + | Netagy | Netagy | Hattie | + | Quility | Quility | Nanette | + | default | null | Dale | + +----------+------------+-------------+ + +### NULLIF + +The \`nullif(field1, field2)\` function returns \`null\` if the values in both fields are identical. If the values differ, the function returns the value in the first field (field1). + +**Argument type:** All supported data types (Note that the semantic check will fail if the parameters are different types.) + +**Return type:** Any + +#### Example + + os> source=accounts | eval result = nullif(employer, 'Pyrami') | fields result, employer, firstname + fetched rows / total rows = 4/4 + +----------+------------+-------------+ + | result | employer | firstname | + |----------+------------+-------------| + | null | Pyrami | Amber | + | Netagy | Netagy | Hattie | + | Quility | Quility | Nanette | + | null | null | Dale | + +----------+------------+-------------+ + +### ISNULL + +The \`isnull(field1, field2)\` function checks for null values and returns \`null\` if the values in both fields are identical. If the values differ, the function returns the value in the first field (field1). + +**Argument type:** All supported data types + +**Return type:** Any + +#### Example + + os> source=accounts | eval result = isnull(employer) | fields result, employer, firstname + fetched rows / total rows = 4/4 + +----------+------------+-------------+ + | result | employer | firstname | + |----------+------------+-------------| + | False | Pyrami | Amber | + | False | Netagy | Hattie | + | False | Quility | Nanette | + | True | null | Dale | + +----------+------------+-------------+ + +### IF + +The \`if(condition, expr1, expr2)\` function returns \`expr1\` if \`condition\` is \`true\`, and \`expr2\` otherwise. + +**Argument type:** All supported data types (Note that the semantic check will fail if \`expr1\` and \`expr2\` have different types.) + +**Return type:** Any + +Example: + + os> source=accounts | eval result = if(true, firstname, lastname) | fields result, firstname, lastname + fetched rows / total rows = 4/4 + +----------+-------------+------------+ + | result | firstname | lastname | + |----------+-------------+------------| + | Amber | Amber | Duke | + | Hattie | Hattie | Bond | + | Nanette | Nanette | Bates | + | Dale | Dale | Adams | + +----------+-------------+------------+ + + os> source=accounts | eval result = if(false, firstname, lastname) | fields result, firstname, lastname + fetched rows / total rows = 4/4 + +----------+-------------+------------+ + | result | firstname | lastname | + |----------+-------------+------------| + | Duke | Amber | Duke | + | Bond | Hattie | Bond | + | Bates | Nanette | Bates | + | Adams | Dale | Adams | + +----------+-------------+------------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/datetime.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/datetime.ts new file mode 100644 index 000000000000..5b2ca67f50c2 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/datetime.ts @@ -0,0 +1,537 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const datetimeFunction = `## Datetime +--- + +### Datetime functions + +PPL functions use the search capabilities of the OpenSearch engine. However, these functions don't execute directly within the OpenSearch plugin's memory. Instead, they facilitate the global filtering of query results based on specific conditions, such as a \`WHERE\` or \`HAVING\` clause. + +The following sections describe the \`datetime\` PPL functions. + +### ADDDATE + +The \`adddate\` function add a time interval to a date. It supports two forms: adding a specified interval using \`INTERVAL\` keyword or adding an integer number of days directly. + +**Argument type:** \`DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG\` + +**Return type:** \`(DATE/DATETIME/TIMESTAMP/STRING, INTERVAL) -> DATETIME\`, \`(DATE, LONG) -> DATE\`, \`(DATETIME/TIMESTAMP/STRING, LONG) -> DATETIME\` + +**Synonyms**: \`[DATE\_ADD](#date_add)\` + +#### Example + + os> source=people | eval \`ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR)\` = ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR), \`ADDDATE(DATE('2020-08-26'), 1)\` = ADDDATE(DATE('2020-08-26'), 1), \`ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1)\` = ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | fields \`ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR)\`, \`ADDDATE(DATE('2020-08-26'), 1)\`, \`ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1)\` + fetched rows / total rows = 1/1 + +------------------------------------------------+----------------------------------+------------------------------------------------+ + | ADDDATE(DATE('2020-08-26'), INTERVAL 1 HOUR) | ADDDATE(DATE('2020-08-26'), 1) | ADDDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | + |------------------------------------------------+----------------------------------+------------------------------------------------| + | 2020-08-26 01:00:00 | 2020-08-27 | 2020-08-27 01:01:01 | + +------------------------------------------------+----------------------------------+------------------------------------------------+ + +#### DATE + +The \`date(expr)\` function converts strings to date types and extracts the date portion from existing date, datetime, and timestamp values. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`DATE\` + +#### Example + + >od source=people | eval \`DATE('2020-08-26')\` = DATE('2020-08-26'), \`DATE(TIMESTAMP('2020-08-26 13:49:00'))\` = DATE(TIMESTAMP('2020-08-26 13:49:00')) | fields \`DATE('2020-08-26')\`, \`DATE(TIMESTAMP('2020-08-26 13:49:00'))\` + fetched rows / total rows = 1/1 + +----------------------+------------------------------------------+ + | DATE('2020-08-26') | DATE(TIMESTAMP('2020-08-26 13:49:00')) | + |----------------------+------------------------------------------| + | DATE '2020-08-26' | DATE '2020-08-26' | + +----------------------+------------------------------------------+ + +#### DATE\_ADD + +The \`date\_add(date, INTERVAL expr unit)\` or \`date\_add(date, expr)\` adds +the time interval specified by \`expr\` to a given \`date\`. It supports adding a specific interval and adding an integer number of days. + +**Argument type:** \`DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG\` + +**Return type:** \`DATE/DATETIME/TIMESTAMP/STRING, INTERVAL ->\`, \`DATETIME\`, \`DATE, LONG -> DATE\`, \`DATETIME/TIMESTAMP/STRING, LONG -> DATETIME\` + +**Synonyms:** \`[ADDDATE](#adddate)\` + +#### Example + + os> source=people | eval \`DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR)\` = DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR), \`DATE_ADD(DATE('2020-08-26'), 1)\` = DATE_ADD(DATE('2020-08-26'), 1), \`DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1)\` = DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1) | fields \`DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR)\`, \`DATE_ADD(DATE('2020-08-26'), 1)\`, \`DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1)\` + fetched rows / total rows = 1/1 + +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ + | DATE_ADD(DATE('2020-08-26'), INTERVAL 1 HOUR) | DATE_ADD(DATE('2020-08-26'), 1) | DATE_ADD(TIMESTAMP('2020-08-26 01:01:01'), 1) | + |-------------------------------------------------+-----------------------------------+-------------------------------------------------| + | 2020-08-26 01:00:00 | 2020-08-27 | 2020-08-27 01:01:01 | + +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ + +### DATE\_FORMAT + +The \`date\_format(date, format)\` function takes a date and a format string as arguments and returns the formatted date string according to the specified format. + +The following table lists the available specifier arguments. + +| Specifier | Description | +|-----------|-----------------------------------------------------------| +| %a | Abbreviated weekday name (Sun..Sat) | +| %b | Abbreviated month name (Jan..Dec) | +| %c | Month, numeric (0..12) | +| %D | Day of the month with English suffix (0th, 1st, 2nd, 3rd, …) | +| %d | Day of the month, numeric (00..31) | +| %e | Day of the month, numeric (0..31) | +| %f | Microseconds (000000..999999) | +| %H | Hour (00..23) | +| %h | Hour (01..12) | +| %I | Hour (01..12) | +| %i | Minutes, numeric (00..59) | +| %j | Day of year (001..366) | +| %k | Hour (0..23) | +| %l | Hour (1..12) | +| %M | Month name (January..December) | +| %m | Month, numeric (00..12) | +| %p | AM or PM | +| %r | Time, 12-hour (hh:mm:ss followed by AM or PM) | +| %S | Seconds (00..59) | +| %s | Seconds (00..59) | +| %T | Time, 24-hour (hh:mm:ss) | +| %U | Week (00..53), where Sunday is the first day of the week; WEEK() mode 0 | +| %u | Week (00..53), where Monday is the first day of the week; WEEK() mode 1 | +| %V | Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X | +| %v | Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x | +| %W | Weekday name (Sunday..Saturday) | +| %w | Day of the week (0=Sunday..6=Saturday) | +| %X | Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V | +| %x | Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v | +| %Y | Year, numeric, four digits | +| %y | Year, numeric (two digits) | +| %% | A literal % character | +| %x | x, for any “x” not listed above | + +**Argument type:** STRING/DATE/DATETIME/TIMESTAMP, STRING + +**Return type:** STRING + +#### Example + + >od source=people | eval \`DATE_FORMAT('1998-01-31 13:14:15.012345', '%T.%f')\` = DATE_FORMAT('1998-01-31 13:14:15.012345', '%T.%f'), \`DATE_FORMAT(TIMESTAMP('1998-01-31 13:14:15.012345'), '%Y-%b-%D %r')\` = DATE_FORMAT(TIMESTAMP('1998-01-31 13:14:15.012345'), '%Y-%b-%D %r') | fields \`DATE_FORMAT('1998-01-31 13:14:15.012345', '%T.%f')\`, \`DATE_FORMAT(TIMESTAMP('1998-01-31 13:14:15.012345'), '%Y-%b-%D %r')\` + fetched rows / total rows = 1/1 + +-----------------------------------------------+----------------------------------------------------------------+ + | DATE('1998-01-31 13:14:15.012345', '%T.%f') | DATE(TIMESTAMP('1998-01-31 13:14:15.012345'), '%Y-%b-%D %r') | + |-----------------------------------------------+----------------------------------------------------------------| + | '13:14:15.012345' | '1998-Jan-31st 01:14:15 PM' | + +-----------------------------------------------+----------------------------------------------------------------+ + +### DATE\_SUB + +**Description** + +Usage: date\_sub(date, INTERVAL expr unit)/ date\_sub(date, expr) +subtracts the time interval expr from date + +Argument type: \`DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG\` + +**Return type:** \`DATE/DATETIME/TIMESTAMP/STRING, INTERVAL -> DATETIME\`, \`DATE, LONG -> DATE\`, \`DATETIME/TIMESTAMP/STRING, LONG -> DATETIME\` + +**Synonyms:** \`[SUBDATE](#subdate)\` + +#### Example + + os> source=people | eval \`DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY)\` = DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY), \`DATE_SUB(DATE('2020-08-26'), 1)\` = DATE_SUB(DATE('2020-08-26'), 1), \`DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1)\` = DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1) | fields \`DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY)\`, \`DATE_SUB(DATE('2020-08-26'), 1)\`, \`DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1)\` + fetched rows / total rows = 1/1 + +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ + | DATE_SUB(DATE('2008-01-02'), INTERVAL 31 DAY) | DATE_SUB(DATE('2020-08-26'), 1) | DATE_SUB(TIMESTAMP('2020-08-26 01:01:01'), 1) | + |-------------------------------------------------+-----------------------------------+-------------------------------------------------| + | 2007-12-02 | 2020-08-25 | 2020-08-25 01:01:01 | + +-------------------------------------------------+-----------------------------------+-------------------------------------------------+ + +### DAY + +The \`day(date)\` function retrieves the day of the month (1-31) for a provided \`date\`. Note that dated with a value of 0, such as "0000-00-00" or "2008-00-00", are considered invalid. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +**Synonyms:** \`DAYOFMONTH\` + +#### Example + + os> source=people | eval \`DAY(DATE('2020-08-26'))\` = DAY(DATE('2020-08-26')) | fields \`DAY(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +---------------------------+ + | DAY(DATE('2020-08-26')) | + |---------------------------| + | 26 | + +---------------------------+ + +### DAYNAME + +The \`dayname(date)\` function retrieves the full name of the weekday, for example, Monday, Tuesday, and so forth, for a given \`date\`. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`DAYNAME(DATE('2020-08-26'))\` = DAYNAME(DATE('2020-08-26')) | fields \`DAYNAME(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +-------------------------------+ + | DAYNAME(DATE('2020-08-26')) | + |-------------------------------| + | Wednesday | + +-------------------------------+ + +### DAYOFMONTH + +The \`dayofmonth(date)\` function retrieves the day of the month (1-31) for a provided \`date\`. Note that dated with a value of 0, such as "0000-00-00" or "2008-00-00", are considered invalid. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +**Synonyms:** \`DAY\` + +#### Example + + os> source=people | eval \`DAYOFMONTH(DATE('2020-08-26'))\` = DAYOFMONTH(DATE('2020-08-26')) | fields \`DAYOFMONTH(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +----------------------------------+ + | DAYOFMONTH(DATE('2020-08-26')) | + |----------------------------------| + | 26 | + +----------------------------------+ + +### DAYOFWEEK + +The \`dayofweek(date)\` retrieves the numerical index (1-7) representing the weekday for a given \`date\`, where 1 corresponds to Sunday and 7 corresponds to Saturday. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`DAYOFWEEK(DATE('2020-08-26'))\` = DAYOFWEEK(DATE('2020-08-26')) | fields \`DAYOFWEEK(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +---------------------------------+ + | DAYOFWEEK(DATE('2020-08-26')) | + |---------------------------------| + | 4 | + +---------------------------------+ + +### DAYOFYEAR + +The \`dayofyear(date)\` function retrieves the day of the year for a given \`date\`, ranging from 1 to 366. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`DAYOFYEAR(DATE('2020-08-26'))\` = DAYOFYEAR(DATE('2020-08-26')) | fields \`DAYOFYEAR(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +---------------------------------+ + | DAYOFYEAR(DATE('2020-08-26')) | + |---------------------------------| + | 239 | + +---------------------------------+ + +### FROM\_DAYS + +The \`from\_days(N)\` function retrieves the date value corresponding to the provided day number \`N\`. + +**Argument type:** \`INTEGER/LONG\` + +**Return type:** \`DATE\` + +#### Example + + os> source=people | eval \`FROM_DAYS(733687)\` = FROM_DAYS(733687) | fields \`FROM_DAYS(733687)\` + fetched rows / total rows = 1/1 + +---------------------+ + | FROM_DAYS(733687) | + |---------------------| + | 2008-10-07 | + +---------------------+ + +### HOUR + +The \`hour(time)\` function extracts the hour value from a given \`time\`. Unlike the typical time-of-day format wher hours range from 0 to 23, the \`time\` input can have a larger range. Therefore, the \`hour(time)\` function may return values exceeding 23. + +**Argument type:** \`STRING/TIME/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`HOUR(TIME('01:02:03'))\` = HOUR(TIME('01:02:03')) | fields \`HOUR(TIME('01:02:03'))\` + fetched rows / total rows = 1/1 + +--------------------------+ + | HOUR(TIME('01:02:03')) | + |--------------------------| + | 1 | + +--------------------------+ + +### MAKETIME + +**Function signature:** \`MAKETIME(INTEGER, INTEGER, INTEGER) -> DATE\` + +### MICROSECOND + +The \`microsecond(expr)\` function retrieves the microsecond portion (0-999999) from a given \`time\` or \`datetime\` expression. + +**Argument type:** \`STRING/TIME/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`MICROSECOND(TIME('01:02:03.123456'))\` = MICROSECOND(TIME('01:02:03.123456')) | fields \`MICROSECOND(TIME('01:02:03.123456'))\` + fetched rows / total rows = 1/1 + +----------------------------------------+ + | MICROSECOND(TIME('01:02:03.123456')) | + |----------------------------------------| + | 123456 | + +----------------------------------------+ + +### MINUTE + +The \`minute(time)\` extracts the minute value (0-59) from a given \`time\` expression. + +**Argument type:** \`STRING/TIME/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`MINUTE(TIME('01:02:03'))\` = MINUTE(TIME('01:02:03')) | fields \`MINUTE(TIME('01:02:03'))\` + fetched rows / total rows = 1/1 + +----------------------------+ + | MINUTE(TIME('01:02:03')) | + |----------------------------| + | 2 | + +----------------------------+ + +### MONTH + +The \`month(date)\` function extracts the month (1-12) from a valid \`date\` value. However, invalid dates containing 0 values for the month, such as "0000-00-00" or "2008-00-00" are considered invalid. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`MONTH(DATE('2020-08-26'))\` = MONTH(DATE('2020-08-26')) | fields \`MONTH(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +-----------------------------+ + | MONTH(DATE('2020-08-26')) | + |-----------------------------| + | 8 | + +-----------------------------+ + +### MONTHNAME + +The \`monthname(date)\` function retrieves the full name of the month, for example, January, February, and so forth, for a given \`date\`. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`MONTHNAME(DATE('2020-08-26'))\` = MONTHNAME(DATE('2020-08-26')) | fields \`MONTHNAME(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +---------------------------------+ + | MONTHNAME(DATE('2020-08-26')) | + |---------------------------------| + | August | + +---------------------------------+ + +### NOW + +**Function signature:** NOW() -> DATE + +### QUARTER + +The \`quarter(date)\` function retrieves the quarter (1-4) for a given \`date\`. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`QUARTER(DATE('2020-08-26'))\` = QUARTER(DATE('2020-08-26')) | fields \`QUARTER(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +-------------------------------+ + | QUARTER(DATE('2020-08-26')) | + |-------------------------------| + | 3 | + +-------------------------------+ + +### SECOND + +The \`second(time)\` function extracts the second value (0-59) from a given \`time\` expression. + +**Argument type:** \`STRING/TIME/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`SECOND(TIME('01:02:03'))\` = SECOND(TIME('01:02:03')) | fields \`SECOND(TIME('01:02:03'))\` + fetched rows / total rows = 1/1 + +----------------------------+ + | SECOND(TIME('01:02:03')) | + |----------------------------| + | 3 | + +----------------------------+ + +### SUBDATE + +The \`subdate(date, INTERVAL expr unit)\` or \`subdate(date, expr)\` function subtracts a time interval from a date. + +**Argument type:** \`DATE/DATETIME/TIMESTAMP/STRING, INTERVAL/LONG\` + +**Return type:** \`DATE/DATETIME/TIMESTAMP/STRING, INTERVAL -> DATETIME\`, \`DATE, LONG -> DATE\`, \`DATETIME/TIMESTAMP/STRING, LONG -> DATETIME\` + +**Synonyms:** \`[DATE\_SUB](#date_sub)\` + +#### Example + + os> source=people | eval \`SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY)\` = SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY), \`SUBDATE(DATE('2020-08-26'), 1)\` = SUBDATE(DATE('2020-08-26'), 1), \`SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1)\` = SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | fields \`SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY)\`, \`SUBDATE(DATE('2020-08-26'), 1)\`, \`SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1)\` + fetched rows / total rows = 1/1 + +------------------------------------------------+----------------------------------+------------------------------------------------+ + | SUBDATE(DATE('2008-01-02'), INTERVAL 31 DAY) | SUBDATE(DATE('2020-08-26'), 1) | SUBDATE(TIMESTAMP('2020-08-26 01:01:01'), 1) | + |------------------------------------------------+----------------------------------+------------------------------------------------| + | 2007-12-02 | 2020-08-25 | 2020-08-25 01:01:01 | + +------------------------------------------------+----------------------------------+------------------------------------------------+ + +### TIME + +The \`time(expr)\` function has dual functionality. If \`expr\` is a string, it contructs a \`time\` object from the provided time value format. Conversly, for input of the type \`date\`, \`datetime\`. \`time\`, or \`timestamp\`, it extracts and returns the pure time component from the given expression. + +**Argument type:** \`STRING/DATE/DATETIME/TIME/TIMESTAMP\` + +**Return type:** \`TIME\` + +#### Example + + >od source=people | eval \`TIME('13:49:00')\` = TIME('13:49:00'), \`TIME(TIMESTAMP('2020-08-26 13:49:00'))\` = TIME(TIMESTAMP('2020-08-26 13:49:00')) | fields \`TIME('13:49:00')\`, \`TIME(TIMESTAMP('2020-08-26 13:49:00'))\` + fetched rows / total rows = 1/1 + +--------------------+------------------------------------------+ + | TIME('13:49:00') | TIME(TIMESTAMP('2020-08-26 13:49:00')) | + |--------------------+------------------------------------------| + | TIME '13:49:00' | TIME '13:49:00' | + +--------------------+------------------------------------------+ + +### TIME\_TO\_SEC + +The \`time\_to\_sec(time)\` function transforms a given \`time\` value into its corresponding number of seconds. + +**Argument type:** \`STRING/TIME/DATETIME/TIMESTAMP\` + +**Return type:** \`LONG\` + +#### Example + + os> source=people | eval \`TIME_TO_SEC(TIME('22:23:00'))\` = TIME_TO_SEC(TIME('22:23:00')) | fields \`TIME_TO_SEC(TIME('22:23:00'))\` + fetched rows / total rows = 1/1 + +---------------------------------+ + | TIME_TO_SEC(TIME('22:23:00')) | + |---------------------------------| + | 80580 | + +---------------------------------+ + +### TIMESTAMP + +The \`timestamp(expr)\` function serves a dual purpose: it can both construct a timestamp object from a string representing a time value or act as a caster, converting exsiting date, datetime, or timestamp objects to a standardized timestamp type with the default UTC time zone. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`TIMESTAMP\` + +#### Example + + >od source=people | eval \`TIMESTAMP('2020-08-26 13:49:00')\` = TIMESTAMP('2020-08-26 13:49:00') | fields \`TIMESTAMP('2020-08-26 13:49:00')\` + fetched rows / total rows = 1/1 + +------------------------------------+ + | TIMESTAMP('2020-08-26 13:49:00') | + |------------------------------------| + | TIMESTAMP '2020-08-26 13:49:00 | + +------------------------------------+ + +### TO\_DAYS + +The \`to\_days(date)\` function calculates the number of days that have elapsed since the year 0 for a given \`date\`. If the provided date is invalid, it returns \`NULL\`. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`LONG\` + +#### Example + + os> source=people | eval \`TO_DAYS(DATE('2008-10-07'))\` = TO_DAYS(DATE('2008-10-07')) | fields \`TO_DAYS(DATE('2008-10-07'))\` + fetched rows / total rows = 1/1 + +-------------------------------+ + | TO_DAYS(DATE('2008-10-07')) | + |-------------------------------| + | 733687 | + +-------------------------------+ + +### WEEK + +The \`week(date\[, mode\])\` function extracts the week number for a given \`date\`. If the mode argument is omitted, the default mode 0 is used. The following table lists the mode arguments. + +| Mode | First day of week | Range | Week 1 is the first week … | +|------|-------------------|-------|-------------------------------| +| 0 | Sunday | 0-53 | with a Sunday in this year | +| 1 | Monday | 0-53 | with 4 or more days this year | +| 2 | Sunday | 1-53 | with a Sunday in this year | +| 3 | Monday | 1-53 | with 4 or more days this year | +| 4 | Sunday | 0-53 | with 4 or more days this year | +| 5 | Monday | 0-53 | with a Monday in this year | +| 6 | Sunday | 1-53 | with 4 or more days this year | +| 7 | Monday | 1-53 | with a Monday in this year | + +**Argument type:** \`DATE/DATETIME/TIMESTAMP/STRING\` + +**Return type:** \`INTEGER\` + +#### Example + + >od source=people | eval \`WEEK(DATE('2008-02-20'))\` = WEEK(DATE('2008-02-20')), \`WEEK(DATE('2008-02-20'), 1)\` = WEEK(DATE('2008-02-20'), 1) | fields \`WEEK(DATE('2008-02-20'))\`, \`WEEK(DATE('2008-02-20'), 1)\` + fetched rows / total rows = 1/1 + +----------------------------+-------------------------------+ + | WEEK(DATE('2008-02-20')) | WEEK(DATE('2008-02-20'), 1) | + |----------------------------|-------------------------------| + | 7 | 8 | + +----------------------------+-------------------------------+ + +### YEAR + +The \`year(date)\` function extracts the year component from a given \`date\` value. However, it only returns valid years within the range of 1000 to 9999. If the provided date is invalid or falls outside this range, the function returns 0. + +**Argument type:** \`STRING/DATE/DATETIME/TIMESTAMP\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`YEAR(DATE('2020-08-26'))\` = YEAR(DATE('2020-08-26')) | fields \`YEAR(DATE('2020-08-26'))\` + fetched rows / total rows = 1/1 + +----------------------------+ + | YEAR(DATE('2020-08-26')) | + |----------------------------| + | 2020 | + +----------------------------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/full_text_search.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/full_text_search.ts new file mode 100644 index 000000000000..7f31bae65166 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/full_text_search.ts @@ -0,0 +1,78 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const fullTextSearchFunction = `## Full-text search +--- + +### Full-text search function + +PPL functions use the search capabilities of the OpenSearch engine. However, these functions don't execute directly within the OpenSearch plugin's memory. Instead, they facilitate the global filtering of query results based on specific conditions, such as a \`WHERE\` or \`HAVING\` clause. + +Full-text search allows for searching by full-text queries. For details about full-text search in OpenSearch, see the [Full-text search](https://opensearch.org/docs/latest/search-plugins/sql/full-text/) documentation. + +### MATCH + +The \`match\` function maps user-defined criteria to OpenSearch queries, returning documents that match specific text, number, date, or Boolean values. + +The function signature is \`match(field_expression, query_expression[, option=]*)\`. + +The available parameters are: + +- analyzer +- auto\_generate\_synonyms\_phrase +- fuzziness +- max\_expansions +- prefix\_length +- fuzzy\_transpositions +- fuzzy\_rewrite +- lenient +- operator +- minimum\_should\_match +- zero\_terms\_query +- boost + +**Example 1: Using specific expressions and default values** + +The following example PPL query uses only the \`field\` and \`query\` expressions, with all other parameters set to their default values: + + os> source=accounts | where match(address, 'Street') | fields lastname, address; + fetched rows / total rows = 2/2 + +------------+--------------------+ + | lastname | address | + |------------+--------------------| + | Bond | 671 Bristol Street | + | Bates | 789 Madison Street | + +------------+--------------------+ + +**Example 2: Setting custom values for optional parameters** + +The following example PPL query sets custom values for the optional parameters: + + os> source=accounts | where match(firstname, 'Hattie', operator='AND', boost=2.0) | fields lastname; + fetched rows / total rows = 1/1 + +------------+ + | lastname | + |------------| + | Bond | + +------------+ + +### Limitations + +The full-text search functions can be executed only in [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/), not in-memory. + +To ensure optimal performance and avoid translation issues with complex full-text searhes, place them as clauses within the search command. + +#### Example + +The following is an example complex query that could fail because it is difficult to translate to query DSL: + + \`search source = people | rename firstname as name | dedup account_number | fields name, account_number, balance, employer | where match(employer, 'Open Search') | stats count() by city\` + +To optimize full-text search performance, rewrite the query by placing the \`WHERE\` clause with the full-text search function as the second command after the \`SEARCH\` command. This ensures the full-text search gets pushed down to query DSL. The following is an example query: + + \`search source = people | where match(employer, 'Open Search') | rename firstname as name | dedup account_number | fields name, account_number, balance, employer | stats count() by city\` + +For details about query engine optimization, see the [Optimizations](https://github.com/opensearch-project/sql/blob/22924b13d9cb46759c8d213a7ce903effe06ab47/docs/user/optimization/optimization.rst) developer documentation on GitHub. +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/index.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/index.ts new file mode 100644 index 000000000000..e061c6188e43 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { datetimeFunction } from './datetime'; +export { conditionFunction } from './condition'; +export { mathFunction } from './math'; +export { stringFunction } from './string'; +export { fullTextSearchFunction } from './full_text_search'; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/math.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/math.ts new file mode 100644 index 000000000000..ed189c3eb42c --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/math.ts @@ -0,0 +1,518 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const mathFunction = `## Math +--- + +### Math functions + +PPL functions use the search capabilities of the OpenSearch engine. However, these functions don't execute directly within the OpenSearch plugin's memory. Instead, they facilitate the global filtering of query results based on specific conditions, such as a \`WHERE\` or \`HAVING\` clause. + +The following sections describe the \`math\` PPL functions. + +### ABS + +The \`abs\` function is an absolute value function. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +#### Example + + os> source=people | eval \`ABS(-1)\` = ABS(-1) | fields \`ABS(-1)\` + fetched rows / total rows = 1/1 + +-----------+ + | ABS(-1) | + |-----------| + | 1 | + +-----------+ + +### ACOS + +The \`acos(x)\` function is an arc cosine function. The function expects values in the range of \`-1\` to \`1\` and returns \`NULL\` if the values aren't in that range. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`ACOS(0)\` = ACOS(0) | fields \`ACOS(0)\` + fetched rows / total rows = 1/1 + +--------------------+ + | ACOS(0) | + |--------------------| + | 1.5707963267948966 | + +--------------------+ + +### ASIN + +The \`asin(x)\` function is an arc sine function. The function expects values in the range of \`-1\` to \`1\` and returns \`NULL\` if the values aren't in that range. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`ASIN(0)\` = ASIN(0) | fields \`ASIN(0)\` + fetched rows / total rows = 1/1 + +-----------+ + | ASIN(0) | + |-----------| + | 0.0 | + +-----------+ + +### ATAN + +The \`atan(x)\` function is an arc tangent function that returns an arc tangent of a value \`x\`. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`ATAN(2)\` = ATAN(2), \`ATAN(2, 3)\` = ATAN(2, 3) | fields \`ATAN(2)\`, \`ATAN(2, 3)\` + fetched rows / total rows = 1/1 + +--------------------+--------------------+ + | ATAN(2) | ATAN(2, 3) | + |--------------------+--------------------| + | 1.1071487177940904 | 0.5880026035475675 | + +--------------------+--------------------+ + +### ATAN2 + +The \`atan2(y, x)\` function is an arc tangent function that calculates the angle from a specified point to the coordinate origin as measured from the positive x-axis. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`ATAN2(2, 3)\` = ATAN2(2, 3) | fields \`ATAN2(2, 3)\` + fetched rows / total rows = 1/1 + +--------------------+ + | ATAN2(2, 3) | + |--------------------| + | 0.5880026035475675 | + +--------------------+ + +### CEIL + +The \`ceil(x)\` function returns the smallest integer value that is greater than or equal to the specified value. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`CEIL(2.75)\` = CEIL(2.75) | fields \`CEIL(2.75)\` + fetched rows / total rows = 1/1 + +--------------+ + | CEIL(2.75) | + |--------------| + | 3 | + +--------------+ + +### CONV + +The \`CONV(x, a, b)\` function converts the number \`x\` from \`a\` base to \`b\` base. + +**Argument type:** \`x: STRING, a: INTEGER, b: INTEGER\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`CONV('12', 10, 16)\` = CONV('12', 10, 16), \`CONV('2C', 16, 10)\` = CONV('2C', 16, 10), \`CONV(12, 10, 2)\` = CONV(12, 10, 2), \`CONV(1111, 2, 10)\` = CONV(1111, 2, 10) | fields \`CONV('12', 10, 16)\`, \`CONV('2C', 16, 10)\`, \`CONV(12, 10, 2)\`, \`CONV(1111, 2, 10)\` + fetched rows / total rows = 1/1 + +----------------------+----------------------+-------------------+---------------------+ + | CONV('12', 10, 16) | CONV('2C', 16, 10) | CONV(12, 10, 2) | CONV(1111, 2, 10) | + |----------------------+----------------------+-------------------+---------------------| + | c | 44 | 1100 | 15 | + +----------------------+----------------------+-------------------+---------------------+ + +### COS + +The \`cos(x)\` function is a cosine function, with \`x\` in radians. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`COS(0)\` = COS(0) | fields \`COS(0)\` + fetched rows / total rows = 1/1 + +----------+ + | COS(0) | + |----------| + | 1.0 | + +----------+ + +### COT + +The \`cot(x)\` function is a cotangent function. An out-of-range error is returned if \`x\` equals \`0\`. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`COT(1)\` = COT(1) | fields \`COT(1)\` + fetched rows / total rows = 1/1 + +--------------------+ + | COT(1) | + |--------------------| + | 0.6420926159343306 | + +--------------------+ + +### CRC32 + +The \`crc32\` function calculates the cyclic redundancy check (CRC) value of a given string as a 32-bit unsigned value. + +**Argument type:** \`STRING\` + +**Return type:** \`LONG\` + +#### Example + + os> source=people | eval \`CRC32('MySQL')\` = CRC32('MySQL') | fields \`CRC32('MySQL')\` + fetched rows / total rows = 1/1 + +------------------+ + | CRC32('MySQL') | + |------------------| + | 3259397556 | + +------------------+ + +### DEGREES + +The \`degrees(x)\` function converts \`x\` from radians to degrees. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`DEGREES(1.57)\` = DEGREES(1.57) | fields \`DEGREES(1.57)\` + fetched rows / total rows = 1/1 + +-------------------+ + | DEGREES(1.57) | + |-------------------| + | 89.95437383553924 | + +-------------------+ + +### E + +The \`E()\` function returns Euler's number. + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`E()\` = E() | fields \`E()\` + fetched rows / total rows = 1/1 + +-------------------+ + | E() | + |-------------------| + | 2.718281828459045 | + +-------------------+ + +### EXP + +The \`exp(x)\` function returns \`e\` raised to the power of \`x\`. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`EXP(2)\` = EXP(2) | fields \`EXP(2)\` + fetched rows / total rows = 1/1 + +------------------+ + | EXP(2) | + |------------------| + | 7.38905609893065 | + +------------------+ + +### FLOOR + +The \`floor(x)\` function returns the largest integer less than or equal to the specified value. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`FLOOR(2.75)\` = FLOOR(2.75) | fields \`FLOOR(2.75)\` + fetched rows / total rows = 1/1 + +---------------+ + | FLOOR(2.75) | + |---------------| + | 2 | + +---------------+ + +### LN + +The \`ln(x)\` function returns the natural logarithm of \`x\`. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`LN(2)\` = LN(2) | fields \`LN(2)\` + fetched rows / total rows = 1/1 + +--------------------+ + | LN(2) | + |--------------------| + | 0.6931471805599453 | + +--------------------+ + +### LOG + +The \`log(x)\` function returns the natural logarithm of \`x\`. + +**Argument type: \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`LOG(2)\` = LOG(2), \`LOG(2, 8)\` = LOG(2, 8) | fields \`LOG(2)\`, \`LOG(2, 8)\` + fetched rows / total rows = 1/1 + +--------------------+-------------+ + | LOG(2) | LOG(2, 8) | + |--------------------+-------------| + | 0.6931471805599453 | 3.0 | + +--------------------+-------------+ + +### LOG2 + +The \`log2(x)\` function calculates the base-2 logarithm of \`x\`. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`LOG2(8)\` = LOG2(8) | fields \`LOG2(8)\` + fetched rows / total rows = 1/1 + +-----------+ + | LOG2(8) | + |-----------| + | 3.0 | + +-----------+ + +### LOG10 + +The \`log10(x)\` function calculates the base-10 logarithm of \`x\`. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`LOG10(100)\` = LOG10(100) | fields \`LOG10(100)\` + fetched rows / total rows = 1/1 + +--------------+ + | LOG10(100) | + |--------------| + | 2.0 | + +--------------+ + +### MOD + +The \`MOD(n, m)\` function calculates the remainder of the number \`n\` divided by \`m\`. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** If \`m\` is a nonzero value, a type greater in size between types \`n\` and \`m\` is returned. If \`m\` equals \`0\`, \`NULL\` is returned. + +#### Example + + os> source=people | eval \`MOD(3, 2)\` = MOD(3, 2), \`MOD(3.1, 2)\` = MOD(3.1, 2) | fields \`MOD(3, 2)\`, \`MOD(3.1, 2)\` + fetched rows / total rows = 1/1 + +-------------+---------------+ + | MOD(3, 2) | MOD(3.1, 2) | + |-------------+---------------| + | 1 | 1.1 | + +-------------+---------------+ + +### PI + +The \`PI()\` function returns the constant pi. + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`PI()\` = PI() | fields \`PI()\` + fetched rows / total rows = 1/1 + +-------------------+ + | PI() | + |-------------------| + | 3.141592653589793 | + +-------------------+ + +### POW + +The \`POW(x, y)\` function calculates the value of \`x\` raised to the power of \`y\`. Bad inputs return \`NULL\` results. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +**Synonyms:** \`[POWER](#power)\` + +#### Example + + os> source=people | eval \`POW(3, 2)\` = POW(3, 2), \`POW(-3, 2)\` = POW(-3, 2), \`POW(3, -2)\` = POW(3, -2) | fields \`POW(3, 2)\`, \`POW(-3, 2)\`, \`POW(3, -2)\` + fetched rows / total rows = 1/1 + +-------------+--------------+--------------------+ + | POW(3, 2) | POW(-3, 2) | POW(3, -2) | + |-------------+--------------+--------------------| + | 9.0 | 9.0 | 0.1111111111111111 | + +-------------+--------------+--------------------+ + +### POWER + +The \`POWER(x, y)\` function calculates the value of \`x\` raised to the power of \`y\`. Bad inputs return \`NULL\` results. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +**Synonyms:** \`[POW](#pow)\` + +#### Example + + os> source=people | eval \`POWER(3, 2)\` = POWER(3, 2), \`POWER(-3, 2)\` = POWER(-3, 2), \`POWER(3, -2)\` = POWER(3, -2) | fields \`POWER(3, 2)\`, \`POWER(-3, 2)\`, \`POWER(3, -2)\` + fetched rows / total rows = 1/1 + +---------------+----------------+--------------------+ + | POWER(3, 2) | POWER(-3, 2) | POWER(3, -2) | + |---------------+----------------+--------------------| + | 9.0 | 9.0 | 0.1111111111111111 | + +---------------+----------------+--------------------+ + +### RADIANS + +The \`radians(x)\` function converts \`x\` from degrees to radians. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`RADIANS(90)\` = RADIANS(90) | fields \`RADIANS(90)\` + fetched rows / total rows = 1/1 + +--------------------+ + | RADIANS(90) | + |--------------------| + | 1.5707963267948966 | + +--------------------+ + +### RAND + +The \`RAND()/RAND(N)\` function returns a random floating-point value in the range \`0 <= value < 1.0\`. If integer \`N\` is specified, the seed is initialized prior to execution. One implication of this behavior is that with identical argument \`N\`, \`rand(N)\` returns the same value each time and thus produces a repeatable sequence of column values. + +**Argument type:** \`INTEGER\` + +**Return type:** \`FLOAT\` + +#### Example + + os> source=people | eval \`RAND(3)\` = RAND(3) | fields \`RAND(3)\` + fetched rows / total rows = 1/1 + +------------+ + | RAND(3) | + |------------| + | 0.73105735 | + +------------+ + +### ROUND + +The \`ROUND(x, d)\` function rounds the argument \`x\` to \`d\` decimal places. \`d\` defaults to \`0\` if a value is not specified. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`(INTEGER/LONG \[,INTEGER\]) -> LONG (FLOAT/DOUBLE \[,INTEGER\]) ->LONG\` + +#### Example + + os> source=people | eval \`ROUND(12.34)\` = ROUND(12.34), \`ROUND(12.34, 1)\` = ROUND(12.34, 1), \`ROUND(12.34, -1)\` = ROUND(12.34, -1), \`ROUND(12, 1)\` = ROUND(12, 1) | fields \`ROUND(12.34)\`, \`ROUND(12.34, 1)\`, \`ROUND(12.34, -1)\`, \`ROUND(12, 1)\` + fetched rows / total rows = 1/1 + +----------------+-------------------+--------------------+----------------+ + | ROUND(12.34) | ROUND(12.34, 1) | ROUND(12.34, -1) | ROUND(12, 1) | + |----------------+-------------------+--------------------+----------------| + | 12.0 | 12.3 | 10.0 | 12 | + +----------------+-------------------+--------------------+----------------+ + +### SIGN + +The \`sign\` function returns the sign of the argument as -1, 0, or 1, depending on whether the number is negative, zero, or positive. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`SIGN(1)\` = SIGN(1), \`SIGN(0)\` = SIGN(0), \`SIGN(-1.1)\` = SIGN(-1.1) | fields \`SIGN(1)\`, \`SIGN(0)\`, \`SIGN(-1.1)\` + fetched rows / total rows = 1/1 + +-----------+-----------+--------------+ + | SIGN(1) | SIGN(0) | SIGN(-1.1) | + |-----------+-----------+--------------| + | 1 | 0 | -1 | + +-----------+-----------+--------------+ + +### SIN + +The \`sin(x)\` function is a sine function, with \`x\` in radians. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** \`DOUBLE\` + +#### Example + + os> source=people | eval \`SIN(0)\` = SIN(0) | fields \`SIN(0)\` + fetched rows / total rows = 1/1 + +----------+ + | SIN(0) | + |----------| + | 0.0 | + +----------+ + +### SQRT + +The \`sqrt\` function calculates the square root of a non-negative value \`x\`. + +**Argument type:** \`INTEGER/LONG/FLOAT/DOUBLE\` + +**Return type:** (Non-negative) \`INTEGER/LONG/FLOAT/DOUBLE -> DOUBLE\` (Negative) \`INTEGER/LONG/FLOAT/DOUBLE -> NULL\` + +#### Example + + os> source=people | eval \`SQRT(4)\` = SQRT(4), \`SQRT(4.41)\` = SQRT(4.41) | fields \`SQRT(4)\`, \`SQRT(4.41)\` + fetched rows / total rows = 1/1 + +-----------+--------------+ + | SQRT(4) | SQRT(4.41) | + |-----------+--------------| + | 2.0 | 2.1 | + +-----------+--------------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/string.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/string.ts new file mode 100644 index 000000000000..1667b6bafd89 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/functions/string.ts @@ -0,0 +1,215 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const stringFunction = `## String +--- + +### String functions + +PPL functions use the search capabilities of the OpenSearch engine. However, these functions don't execute directly within the OpenSearch plugin's memory. Instead, they facilitate the global filtering of query results based on specific conditions, such as a \`WHERE\` or \`HAVING\` clause. + +The following sections describe the string functions. + +### CONCAT + +The \`CONCAT(str1, str2)\` function returns \`str1\` and \`str\` concatenated strings. + +**Argument type:** \`STRING, STRING\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`CONCAT('hello', 'world')\` = CONCAT('hello', 'world') | fields \`CONCAT('hello', 'world')\` + fetched rows / total rows = 1/1 + +----------------------------+ + | CONCAT('hello', 'world') | + |----------------------------| + | helloworld | + +----------------------------+ + +### CONCAT\_WS + +The \`CONCAT\_WS(sep, str1, str2)\` function concatenates two strings together, using \`sep\` as a separator between them. + +**Argument type:** \`STRING, STRING, STRING\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`CONCAT_WS(',', 'hello', 'world')\` = CONCAT_WS(',', 'hello', 'world') | fields \`CONCAT_WS(',', 'hello', 'world')\` + fetched rows / total rows = 1/1 + +------------------------------------+ + | CONCAT_WS(',', 'hello', 'world') | + |------------------------------------| + | hello,world | + +------------------------------------+ + +### LENGTH + +The \`length(str)\` function returns the length of a string, measured in number of bytes. + +**Function signature:** \`LENGTH(STRING) -> INTEGER\` + +**Argument type:** \`STRING\` + +**Return type:** \`INTEGER\` + +#### Example + + os> source=people | eval \`LENGTH('helloworld')\` = LENGTH('helloworld') | fields \`LENGTH('helloworld')\` + fetched rows / total rows = 1/1 + +------------------------+ + | LENGTH('helloworld') | + |------------------------| + | 10 | + +------------------------+ + +### LIKE + +The \`like(string, PATTERN)\` function returns \`true\` if the string matches the \`PATTERN\` value. The following two wildcards are commonly used with the \`like\` operator: + +- \`%\`: A percent sign represents zero, one, or multiple characters. +- \`_\`: An underscore represents a single character. + +#### Example + + os> source=people | eval \`LIKE('hello world', '_ello%')\` = LIKE('hello world', '_ello%') | fields \`LIKE('hello world', '_ello%')\` + fetched rows / total rows = 1/1 + +---------------------------------+ + | LIKE('hello world', '_ello%') | + |---------------------------------| + | True | + +---------------------------------+ + +### LOWER + +The \`lower(string)\` function converts a string to lowercase. + +**Argument type:** \`STRING\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`LOWER('helloworld')\` = LOWER('helloworld'), \`LOWER('HELLOWORLD')\` = LOWER('HELLOWORLD') | fields \`LOWER('helloworld')\`, \`LOWER('HELLOWORLD')\` + fetched rows / total rows = 1/1 + +-----------------------+-----------------------+ + | LOWER('helloworld') | LOWER('HELLOWORLD') | + |-----------------------+-----------------------| + | helloworld | helloworld | + +-----------------------+-----------------------+ + +### LTRIM + +The \`ltrim(str)\` function trims leading space characters from a string. + +**Argument type:** \`STRING\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`LTRIM(' hello')\` = LTRIM(' hello'), \`LTRIM('hello ')\` = LTRIM('hello ') | fields \`LTRIM(' hello')\`, \`LTRIM('hello ')\` + fetched rows / total rows = 1/1 + +---------------------+---------------------+ + | LTRIM(' hello') | LTRIM('hello ') | + |---------------------+---------------------| + | hello | hello | + +---------------------+---------------------+ + +### RIGHT + +The \`right(str, len)\` function returns the rightmost \`len\` characters from a \`str\` value. \`NULL\` is returned if any argument is null. + +**Argument type:** \`STRING, INTEGER\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`RIGHT('helloworld', 5)\` = RIGHT('helloworld', 5), \`RIGHT('HELLOWORLD', 0)\` = RIGHT('HELLOWORLD', 0) | fields \`RIGHT('helloworld', 5)\`, \`RIGHT('HELLOWORLD', 0)\` + fetched rows / total rows = 1/1 + +--------------------------+--------------------------+ + | RIGHT('helloworld', 5) | RIGHT('HELLOWORLD', 0) | + |--------------------------+--------------------------| + | world | | + +--------------------------+--------------------------+ + +### RTRIM + +The \`rtrim(str)\` function trims trailing space characters from a string. + +**Argument type:** \`STRING\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`RTRIM(' hello')\` = RTRIM(' hello'), \`RTRIM('hello ')\` = RTRIM('hello ') | fields \`RTRIM(' hello')\`, \`RTRIM('hello ')\` + fetched rows / total rows = 1/1 + +---------------------+---------------------+ + | RTRIM(' hello') | RTRIM('hello ') | + |---------------------+---------------------| + | hello | hello | + +---------------------+---------------------+ + +### SUBSTRING + +The \`substring(str, start)\` or \`substring(str, start, length)\`function returns a substring of the input string \`str\`. If \`length\` is not specified, the function returns the entire string from the \`start\` index. + +**Argument type:** \`STRING, INTEGER, INTEGER\` + +**Return type:** \`STRING\` + +**Synonyms:** \`SUBSTR\` + +#### Example + + os> source=people | eval \`SUBSTRING('helloworld', 5)\` = SUBSTRING('helloworld', 5), \`SUBSTRING('helloworld', 5, 3)\` = SUBSTRING('helloworld', 5, 3) | fields \`SUBSTRING('helloworld', 5)\`, \`SUBSTRING('helloworld', 5, 3)\` + fetched rows / total rows = 1/1 + +------------------------------+---------------------------------+ + | SUBSTRING('helloworld', 5) | SUBSTRING('helloworld', 5, 3) | + |------------------------------+---------------------------------| + | oworld | owo | + +------------------------------+---------------------------------+ + +### TRIM + +The \`trim\` function removes leading and trailing white space from a string. + +**Argument type:** \`STRING\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`TRIM(' hello')\` = TRIM(' hello'), \`TRIM('hello ')\` = TRIM('hello ') | fields \`TRIM(' hello')\`, \`TRIM('hello ')\` + fetched rows / total rows = 1/1 + +--------------------+--------------------+ + | TRIM(' hello') | TRIM('hello ') | + |--------------------+--------------------| + | hello | hello | + +--------------------+--------------------+ + +### UPPER + +The \`upper(string)\` function converts a string to uppercase. + +**Argument type:** \`STRING\` + +**Return type:** \`STRING\` + +#### Example + + os> source=people | eval \`UPPER('helloworld')\` = UPPER('helloworld'), \`UPPER('HELLOWORLD')\` = UPPER('HELLOWORLD') | fields \`UPPER('helloworld')\`, \`UPPER('HELLOWORLD')\` + fetched rows / total rows = 1/1 + +-----------------------+-----------------------+ + | UPPER('helloworld') | UPPER('HELLOWORLD') | + |-----------------------+-----------------------| + | HELLOWORLD | HELLOWORLD | + +-----------------------+-----------------------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/groups.tsx b/src/plugins/data/public/query/query_string/language_service/ppl_docs/groups.tsx new file mode 100644 index 000000000000..633def301493 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/groups.tsx @@ -0,0 +1,126 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + dedupCmd, + evalCmd, + fieldsCmd, + headCmd, + parseCmd, + rareCmd, + renameCmd, + searchCmd, + sortCmd, + statsCmd, + syntaxCmd, + topCmd, + whereCmd, +} from './commands'; +import { + mathFunction, + datetimeFunction, + stringFunction, + conditionFunction, + fullTextSearchFunction, +} from './functions'; +import { pplDatatypes, pplIdentifiers } from './language_structure'; + +export const Group1 = { + label: 'Commands', + options: [ + { + label: 'Syntax', + value: syntaxCmd, + }, + { + label: 'dedup', + value: dedupCmd, + }, + { + label: 'eval', + value: evalCmd, + }, + { + label: 'fields', + value: fieldsCmd, + }, + { + label: 'rename', + value: renameCmd, + }, + { + label: 'search', + value: searchCmd, + }, + { + label: 'sort', + value: sortCmd, + }, + { + label: 'stats', + value: statsCmd, + }, + { + label: 'where', + value: whereCmd, + }, + { + label: 'head', + value: headCmd, + }, + { + label: 'parse', + value: parseCmd, + }, + { + label: 'rare', + value: rareCmd, + }, + { + label: 'top', + value: topCmd, + }, + ], +}; + +export const Group2 = { + label: 'Functions', + options: [ + { + label: 'Math', + value: mathFunction, + }, + { + label: 'Date and Time', + value: datetimeFunction, + }, + { + label: 'String', + value: stringFunction, + }, + { + label: 'Condition', + value: conditionFunction, + }, + { + label: 'Full Text Search', + value: fullTextSearchFunction, + }, + ], +}; + +export const Group3 = { + label: 'Language Structure', + options: [ + { + label: 'Identifiers', + value: pplIdentifiers, + }, + { + label: 'Data Types', + value: pplDatatypes, + }, + ], +}; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/datatypes.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/datatypes.ts new file mode 100644 index 000000000000..7914bc628daf --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/datatypes.ts @@ -0,0 +1,326 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const pplDatatypes = `## Data Types +--- + +### Data types + +A data type defines a collection of data type values and a set of predefined operations for those values. PPL supports the following data types: + +.. hlist:: + :columns: 3 + + * array + * binary + * boolean + * byte + * date + * datetime + * double + * float + * geo\_point + * integer + * interval + * ip + * long + * short + * string + * struct + * text + * time + * timestamp + +### Data type mapping + +The following table is a reference guide for the mapping between an OpenSearch data type, a PPL data type, and a SQL data type. + +| OpenSearch type | PPL type | SQL type | +|-----------------|-----------|-----------| +| binary | binary | VARBINARY | +| boolean | boolean | BOOLEAN | +| byte | byte | TINYINT | +| date | timestamp | TIMESTAMP | +| double | double | DOUBLE | +| float | float | REAL | +| half\_float | float | FLOAT | +| integer | integer | INTEGER | +| ip | ip | VARCHAR | +| keyword | string | VARCHAR | +| long | long | BIGINT | +| nested | array | STRUCT | +| object | struct | STRUCT | +| scaled\_float | float | DOUBLE | +| short | byte | SMALLINT | +| text | text | VARCHAR | + +Some PPL types do not correspond to an OpenSearch type. To use functions that require date and time data types, data type conversion must be performed, as described in the following sections. + +### Numeric data types + +Numeric values ranging from -2147483648 to +2147483647 are recognized as +integers, with data type name \`INTEGER\`. For values that fall beyond the specified range, the \`LONG\` data type is assigned during parsing. + +### Date and time data types + +The data types \`date\` and \`time\` represent temporal values. The PPL plugin supports \`date\`, \`time\`, \`datetime\`, \`timestamp\`, and \`interval\`. By default, [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/) uses \`date\` for any date or time types. To integrate with PPL, each data type, excluding \`timestamp\`, contains temporal and time zone information. Use \`datetime\` functions to clarify the date and time types. Note that certain functions may have limitations on the input argument type. See the [Functions](functions.rst) section in this manual for more information. + +#### Date + +The \`date\` data type represents the calendar date, regardless of time zone. A specific date value represents a 24-hour period, but this period differs across time zones and may be subject to variations due to daylight saving time adjustments. Additionally, the date alone does not contain time-specific information. The date values range from '1000-01-01' to '9999-12-31'. + +| Type | Syntax | Range | +|----------|--------------|------------------------------| +| \`date\` | 'yyyy-MM-dd' | '0001-01-01' to '9999-12-31' | + +#### Time + +The \`time\` data type represents the time of day as displayed on a clock or watch, without specifying a particular time zone. It does not include any information about the calendar date. + +| Type | Syntax | Range | +|----------|--------------|------------------------------| +| \`time\` | 'hh:mm:ss\[.fraction\]' | '00:00:00.000000' to '23:59:59.999999' | + +#### Datetime + +The \`datetime\` data type represents a combination of \`date\` and \`time\`. The \`datetime\` data type does not contain time zone information. For an absolute time point that contains both datetime and time zone information, see the [Timestamp](#timestamp) section. + +See the [Conversion between date and time types](#conversion-between-date-and-time-types) section for information about the conversion rule for \`date\` or \`time\` to \`datetime\`. + +| Type | Syntax | Range | +|----------|--------|-------| +| \`datetime\` | 'yyyy-MM-dd hh:mm:ss\[.fraction\]' | '0001-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999' | + +#### Timestamp + +The \`timestamp\` data type represents absolute points in time, unaffected by time zones or conventions. The \`timestamp\` data type differs from other data types in its storage and retrieval behavior. When a timestamp is sorted, it is converted from Coordinated Universal Time (UTC) to the specified time zone. Conversely, when a timestamp is retrieved, it is converted back to UTC before being displayed or used in calculations. This ensures that the timestamp values remain consistent and comparable across different time zones. + +| Type | Syntax | Range | +|-----------|--------|-------| +| Timestamp | 'yyyy-MM-dd hh:mm:ss\[.fraction\]' | '0001-01-01 00:00:01.000000' UTC to '9999-12-31 23:59:59.999999' | + +#### Interval + +The \`interval\` data type represents a span of time encompassing a specified duration or period. + +| Type | Syntax | +|----------|--------------------| +| Interval | INTERVAL expr unit | + +The expression \`expr\` is configured to be repeatedly evaluated to produce a quantitative value. See the [Expressions](expressions.rst) section of this manual for more information. The unit represents the unit used to interpret the quantity, including MICROSECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, and YEAR. The INTERVAL keyword and the unit specifier are not case sensitive. + +Intervals consist of two classes: day-time and year-week. Day-time intervals store days, hours, minutes, seconds, and microseconds. Year-week intervals store years, quarters, months, and weeks. Each type can only be compared to the same type. + +### Date and time conversion + +Date and time types, excluding \`interval\`, can be mutually converted, with some alteration of the value or some information loss, for example, when extracting the \`time\` value from a \`datetime\` value or converting a \`date\` value to a \`datetime\` value. The PPL plugin supports the following conversion rules for each of the types. + +#### \`date\` conversion + +- Because \`date\` does not contain time information, conversion to \`time\` returns a zero time value \`00:00:00\`. +- Converting from \`date\` to \`datetime\` sets the time value to \`00:00:00\` if \`time\` is not provided, for example, \`2020-08-17\` converts to \`2020-08-17 00:00:00\`. +- Converting to \`timestamp\` sets \`time\` to \`00:00:00\` and time zone (UTC by default), for example, \`2020-08-17\` converts to \`2020-08-17 00:00:00 UTC\`. + +#### \`time\` conversion + +- A \`time\` value does not have any date information, so it cannot be converted to other date and time types. + +#### \`datetime\` conversion + +- Converting from \`datetime\` to \`date\` extracts the date component from the \`datetime\` value, for example, \`2020-08-17 14:09:00\` converts to \`2020-08-08\`. +- Converting to \`time\` extracts the time component from the \`datetime\` value, for example, \`2020-08-17 14:09:00\` converts to \`14:09:00\`. +- Because \`datetime\` does not contain time zone information, conversion to \`timestamp\` sets the time zone to the session's time zone, for example, \`2020-08-17 14:09:00\`, with the system time zone set to UTC, for example, \`2020-08-17 14:09:00 UTC\`. + +#### \`timestamp\` conversion + +- Converting from \`timestamp\` to \`date\ extracts the \`date\` and \`time\` values. Converting from \`timestamp\` to \`datetime\` extracts the \`datetime\` value and retains the time zone information. For example, \`2020-08-17 14:09:00 UTC\` converts \`date\` and \`time\` to \`2020-08-17\` and \`14:09:00\` and \`datetime\` to \`2020-08-17 14:09:00\`. + +### String data types + +A \`string\` data type is a series of characters enclosed within single or double quotation marks that serves as a data type for storing text data. + +### Query struct data type + +In PPL, the \`struct\` data type corresponds to the [Object field type in +OpenSearch](https://opensearch.org/docs/latest/field-types/supported-field-types/object-fields/). The \`"."\` is used as the path selector for accessing the inner attribute of the struct data. + +#### Example 1: Struct to store population data + +The following example struct stores population data in an index containing the following fields: deep-nested object field \`city\`, object field of array value \`account\`, and nested field \`projects\`. + + { + "mappings": { + "properties": { + "city": { + "properties": { + "name": { + "type": "keyword" + }, + "location": { + "properties": { + "latitude": { + "type": "double" + } + } + } + } + }, + "account": { + "properties": { + "id": { + "type": "keyword" + } + } + }, + "projects": { + "type": "nested", + "properties": { + "name": { + "type": "keyword" + } + } + } + } + } + } + +#### Example 2: Struct to store employee data + +The following example struct stores employee data and includes a nested field: + + { + "mappings": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "projects": { + "type": "nested", + "properties": { + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword" + } + }, + "fielddata": true + }, + "started_year": { + "type": "long" + } + } + }, + "title": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } + } + +Result set: + + { + "employees_nested" : [ + { + "id" : 3, + "name" : "Bob Smith", + "title" : null, + "projects" : [ + { + "name" : "AWS Redshift Spectrum querying", + "started_year" : 1990 + }, + { + "name" : "AWS Redshift security", + "started_year" : 1999 + }, + { + "name" : "AWS Aurora security", + "started_year" : 2015 + } + ] + }, + { + "id" : 4, + "name" : "Susan Smith", + "title" : "Dev Mgr", + "projects" : [ ] + }, + { + "id" : 6, + "name" : "Jane Smith", + "title" : "Software Eng 2", + "projects" : [ + { + "name" : "AWS Redshift security", + "started_year" : 1998 + }, + { + "name" : "AWS Hello security", + "started_year" : 2015, + "address" : [ + { + "city" : "Dallas", + "state" : "TX" + } + ] + } + ] + } + ] + } + +#### Example 3: Select a struct inner attribute + +The following example PPL query shows how to fetch \`city\` (top level), \`city.name\` (second level), and \`city.location.latitude\` (deeper level) struct data from the results: + + os> source=people | fields city, city.name, city.location.latitude; + fetched rows / total rows = 1/1 + +-----------------------------------------------------+-------------+--------------------------+ + | city | city.name | city.location.latitude | + |-----------------------------------------------------+-------------+--------------------------| + | {'name': 'Seattle', 'location': {'latitude': 10.5}} | Seattle | 10.5 | + +-----------------------------------------------------+-------------+--------------------------+ + +#### Example 4: Group by a struct inner attribute + +The following example PPL query shows how to group by a struct inner attribute: + + os> source=people | stats count() by city.name; + fetched rows / total rows = 1/1 + +-----------+-------------+ + | count() | city.name | + |-----------+-------------| + | 1 | Seattle | + +-----------+-------------+ + +#### Example 5: Select an object field of an array value + +The following example PPL query shows how to select a deeper level for object fields of array values that return the first element in the array. In this example, the document's inner field \`accounts.id\` has three values instead of a tuple: + + os> source = people | fields accounts, accounts.id; + fetched rows / total rows = 1/1 + +------------+---------------+ + | accounts | accounts.id | + |------------+---------------| + | {'id': 1} | 1 | + +------------+---------------+ +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/identifiers.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/identifiers.ts new file mode 100644 index 000000000000..36288736366e --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/identifiers.ts @@ -0,0 +1,71 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const pplIdentifiers = `## Indentifiers +--- + +### Identifiers + +Identifiers are used for naming database objects, such as an index name, a field name, or a custom label. The two types of identifiers are _regular identifiers_ and _delimited identifiers_. + +#### Regular identifiers + +A regular identifier is a string of characters that starts with an ASCII letter (lowercase or uppercase). The subsequent characters can be a combination of letters, digits, or underscores (\`_\`). A regular identifier cannot be a reversed keyword, and white space or other special characters are not allowed. + +The following identifiers are supported by OpenSearch extensions: + +- **Identifiers prefixed by dot \`.\`:** This is called a hidden index. An example is \`.opensearch_dashboards\`. +- **Identifiers prefixed by the \`@\` symbol:** This is common in meta fields generated for data ingestion. +- **Identifiers with \`-\` in the middle:** This is common in index naming conventions with date information. +- **Identifiers with the \`*\` symbol:** This is common in wildcard matches in an index pattern. + +Index names with a date suffix separated by dashes or dots, such as \`cwl-2020.01.11\` or \`logs-7.0-2020.01.11\`, are common in data ingestion. Identifiers used as index names do not need to be enclosed in quotation marks. Additionally, wildcards within date patterns are accepted, enabling data retrieval across indexes covering different date ranges. For example, you can use \`logs-2020.1*\` to search in indexes for October, November, and December 2020. + +#### Example 1: Index pattern without quotes + +The following example PPL query uses an index pattern directly without quotes: + + os> source=accounts | fields account_number, firstname, lastname; + fetched rows / total rows = 4/4 + +------------------+-------------+------------+ + | account_number | firstname | lastname | + |------------------+-------------+------------| + | 1 | Amber | Duke | + | 6 | Hattie | Bond | + | 13 | Nanette | Bates | + | 18 | Dale | Adams | + +------------------+-------------+------------+ + +### Delimited identifiers + +A delimited identifier is an identifier enclosed in backticks \`\` that contains special characters not permitted in regular identifiers. This allows for the use of characters that would otherwise violate the naming rules for identifiers. + +#### Use cases + +Common use cases for delimited identifiers include the following: + +- Identifiers that coincide with reserved keywords. +- Identifiers that contain a dot \`.\` or a dash \`-\` need to be distinguished from regular identifiers with qualifiers. Enclosing such identifiers in backticks \`\` allows for the parser to differentiate them from qualified identifiers and enables date information within index names. +- Identifiers with special characters in index names. Note that OpenSearch permits the use of special characters, including Unicode characters. + +#### Example 2: Index name enclosed in backticks + +The following example PPL query uses an index name enclosed in backticks \`\`: + + os> source=\`accounts\` | fields \`account_number\`; + fetched rows / total rows = 4/4 + +------------------+ + | account_number | + |------------------| + | 1 | + | 6 | + | 13 | + | 18 | + +------------------+ + +### Case sensitivity + +Identifiers are case sensitive and must match what is stored in OpenSearch. For example, if you run \`source=Accounts\`, an error \`index not found\` occurs \` because the index name \`accounts\` is lowercase. +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/index.ts b/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/index.ts new file mode 100644 index 000000000000..75423e184c08 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/language_structure/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { pplDatatypes } from './datatypes'; +export { pplIdentifiers } from './identifiers'; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_docs/overview.tsx b/src/plugins/data/public/query/query_string/language_service/ppl_docs/overview.tsx new file mode 100644 index 000000000000..5c8d92e57df4 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_docs/overview.tsx @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const overview = `## Overview +--- +Piped Processing Language (PPL) is a query language that processes data in a sequential, step-by-step manner. PPL uses a set of commands, connected by pipes (|), to process data and return results (note that the requests and results are read-only in OpenSearch). + +You can query data in OpenSearch using [PPL](https://opensearch.org/docs/latest/search-plugins/sql/ppl/index/), [query domain-specific language (DSL)](https://opensearch.org/docs/latest/query-dsl/index/), or [SQL](https://opensearch.org/docs/latest/search-plugins/sql/sql/index/). + +PPL is the primary language used for observability tasks in OpenSearch. Developers, DevOps engineers, support engineers, site reliability engineers, and IT managers find it useful for exploring and discovering log, monitoring, and observability data. For example, you can use PPL to: + +- Find all log messages that contain a specific error code. +- Identify trends in your data over time. +- Group similar data points. +- Calculate statistics for your data. + +PPL is available in OpenSearch Dashboards and as a standalone command-line tool. Within OpenSearch Dashboards, you can use [Query Workbench](https://opensearch.org/docs/latest/dashboards/query-workbench/) to run on-demand PPL commands and view and save the results as both text and JSON. The [PPL command line interface (CLI)](https://opensearch.org/docs/latest/search-plugins/sql/cli/) is a standalone Python application that you can launch with the \`opensearchsql\` command and then run on-demand PPL commands and view and save the results as both text and JSON. + +Here is an example of a PPL query. This query retrieves the first and last names of all accounts for which the age is greater than 18. + +\`\`\` +source=accounts +| where age > 18 +| fields firstname, lastname +\`\`\` +`; diff --git a/src/plugins/data/public/query/query_string/language_service/ppl_reference_flyout.tsx b/src/plugins/data/public/query/query_string/language_service/ppl_reference_flyout.tsx new file mode 100644 index 000000000000..220dc1ffecc1 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/ppl_reference_flyout.tsx @@ -0,0 +1,101 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiComboBoxOptionOption, + EuiCompressedComboBox, + EuiFlexGroup, + EuiFlexItem, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiLink, + EuiMarkdownFormat, + EuiSmallButton, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import { FlyoutContainers } from './flyout_containers'; +import { Group1, Group2, Group3 } from './ppl_docs/groups'; +import { overview } from './ppl_docs/overview'; + +interface Props { + module: string; + onClose: () => void; +} + +export const PPLReferenceFlyout = ({ module, onClose }: Props) => { + const allOptionsStatic = [{ label: 'Overview', value: overview }, Group1, Group2, Group3]; + const defaultOption = [allOptionsStatic[0]]; + const [selectedOptions, setSelected] = useState(defaultOption); + const [flyoutContent, setFlyoutContent] = useState( + {defaultOption[0].value} + ); + + const onChange = (SelectedOptions: any) => { + setSelected(SelectedOptions); + + const newContent = SelectedOptions.map((option: EuiComboBoxOptionOption) => ( + {option.value} + )); + setFlyoutContent(newContent); + }; + + const flyoutHeader = ( + + +

OpenSearch PPL Reference Manual

+
+
+ ); + + const PPL_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/search-plugins/sql/ppl/index'; + + const flyoutBody = ( + + + + + + + + + Learn More + + + + + + {flyoutContent} + + ); + + const flyoutFooter = ( + + + + Close + + + + ); + + return ( + + ); +}; diff --git a/src/plugins/data/public/query/query_string/language_service/recent_query.tsx b/src/plugins/data/public/query/query_string/language_service/recent_query.tsx new file mode 100644 index 000000000000..d058cb5c692a --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/recent_query.tsx @@ -0,0 +1,169 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import './_recent_query.scss'; + +import { + EuiBasicTable, + EuiButtonEmpty, + EuiButtonIcon, + EuiCopy, + EuiPopover, + EuiText, +} from '@elastic/eui'; +import moment from 'moment'; + +import React, { useCallback, useEffect, useState } from 'react'; +import { Query, TimeRange } from 'src/plugins/data/common'; +import { QueryStringContract } from '../query_string_manager'; + +// TODO: Need to confirm this number +export const MAX_RECENT_QUERY_SIZE = 10; + +interface RecentQueryItem { + query: Query; + time: number; + timeRange?: TimeRange; +} + +export function RecentQuery(props: { + queryString: QueryStringContract; + query: Query; + onClickRecentQuery: (query: Query, timeRange?: TimeRange) => void; +}) { + const [recentQueries, setRecentQueries] = useState( + props.queryString.getQueryHistory() + ); + const [isPopoverOpen, setPopover] = useState(false); + const onButtonClick = () => { + setPopover(!isPopoverOpen); + }; + + const clearHistory = useCallback(() => { + props.queryString?.clearQueryHistory(); + setRecentQueries(props.queryString?.getQueryHistory()); + }, [props.queryString]); + + const clear = () => { + clearHistory(); + }; + + useEffect(() => { + const done = props.queryString.changeQueryHistory(setRecentQueries); + return () => done(); + }, [props.queryString]); + + const getRowProps = (item: any) => { + const { id } = item; + return { + 'data-test-subj': `row-${id}`, + className: 'customRowClass', + onClick: () => {}, + }; + }; + + const getCellProps = (item: any, column: any) => { + const { id } = item; + const { field } = column; + return { + className: 'customCellClass', + 'data-test-subj': `cell-${id}-${field}`, + textOnly: true, + }; + }; + + const actions = [ + { + name: 'Run', + description: 'Run recent query', + icon: 'play', + type: 'icon', + onClick: (item) => { + props.onClickRecentQuery(recentQueries[item.id].query, recentQueries[item.id].timeRange); + setPopover(false); + }, + 'data-test-subj': 'action-run', + }, + { + render: (item) => { + return ( + + {(copy) => ( + + )} + + ); + }, + }, + ]; + + const tableColumns = [ + { + field: 'query', + name: 'Recent query', + }, + { + field: 'language', + name: 'Language', + }, + { + field: 'time', + name: 'Last run', + }, + { name: 'Actions', actions }, + ]; + + const recentQueryItems = recentQueries + .filter((item, idx) => idx < MAX_RECENT_QUERY_SIZE) + .map((query, idx) => { + const date = moment(query.time); + + const formattedDate = date.format('MMM D, YYYY HH:mm:ss'); + + let queryLanguage = query.query.language; + if (queryLanguage === 'kuery') { + queryLanguage = 'DQL'; + } + + const tableItem = { + id: idx, + query: query.query.query, + timeRange: query.timeRange, + language: queryLanguage, + time: formattedDate, + }; + + return tableItem; + }); + + return ( + + + {'Recent queries'} + + + } + isOpen={isPopoverOpen} + closePopover={() => setPopover(false)} + panelPaddingSize="none" + anchorPosition={'downRight'} + > + + + ); +} diff --git a/src/plugins/data/public/query/query_string/language_service/sql_reference_flyout.tsx b/src/plugins/data/public/query/query_string/language_service/sql_reference_flyout.tsx new file mode 100644 index 000000000000..40b849fb72d7 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/sql_reference_flyout.tsx @@ -0,0 +1,61 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiComboBoxOptionOption, + EuiCompressedComboBox, + EuiFlexGroup, + EuiFlexItem, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiLink, + EuiMarkdownFormat, + EuiSmallButton, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import { FlyoutContainers } from './flyout_containers'; +import { Group1, Group2, Group3 } from './ppl_docs/groups'; +import { overview } from './ppl_docs/overview'; + +interface Props { + module: string; + onClose: () => void; +} + +export const SQLReferenceFlyout = ({ module, onClose }: Props) => { + const flyoutHeader = ( + + +

OpenSearch SQL Reference Manual

+
+
+ ); + + const flyoutBody = null; + + const flyoutFooter = ( + + + + Close + + + + ); + + return ( + + ); +}; diff --git a/src/plugins/data/public/query/query_string/query_history.ts b/src/plugins/data/public/query/query_string/query_history.ts index 80dfa4b5d560..04e2285add1c 100644 --- a/src/plugins/data/public/query/query_string/query_history.ts +++ b/src/plugins/data/public/query/query_string/query_history.ts @@ -35,7 +35,7 @@ export class QueryHistory { return () => subscription.unsubscribe(); } - addQueryToHistory(dataset: Dataset, query: Query, dateRange?: TimeRange) { + addQueryToHistory(query: Query, dateRange?: TimeRange) { const keys = this.getHistoryKeys(); keys.splice(0, 500); // only maintain most recent X; keys.forEach((key) => { @@ -45,7 +45,6 @@ export class QueryHistory { const timestamp = new Date().getTime(); const k = 'query_' + timestamp; this.storage.set(k, { - dataset, time: timestamp, query, dateRange, diff --git a/src/plugins/data/public/query/query_string/query_string_manager.ts b/src/plugins/data/public/query/query_string/query_string_manager.ts index 6bbc5706b64b..754b444435c0 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.ts @@ -112,9 +112,9 @@ export class QueryStringManager { }; // Todo: update this function to use the Query object when it is udpated, Query object should include time range and dataset - public addToQueryHistory(dataSet: Dataset, query: Query, timeRange?: TimeRange) { + public addToQueryHistory(query: Query, timeRange?: TimeRange) { if (query.query) { - this.queryHistory.addQueryToHistory(dataSet, query, timeRange); + this.queryHistory.addQueryToHistory(query, timeRange); } } diff --git a/src/plugins/data/public/ui/filter_bar/filter_options.tsx b/src/plugins/data/public/ui/filter_bar/filter_options.tsx index 3edd47e3fddc..131d317ecbc5 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_options.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_options.tsx @@ -55,6 +55,7 @@ import { unpinFilter, UI_SETTINGS, IIndexPattern, + isQueryStringFilter, } from '../../../common'; import { FilterEditor } from './filter_editor'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; @@ -75,6 +76,7 @@ interface Props { onFiltersUpdated?: (filters: Filter[]) => void; loadedSavedQuery?: SavedQuery; useSaveQueryMenu: boolean; + isQueryEditorControl: boolean; } const maxFilterWidth = 600; @@ -371,7 +373,10 @@ const FilterOptionsUI = (props: Props) => { className="osdSavedQueryManagement__popoverButton" title={label} > - + ); @@ -398,6 +403,25 @@ const FilterOptionsUI = (props: Props) => { ); + if (props.isQueryEditorControl) { + return ( + + {saveQueryPanel} + + ); + } + return ( void; editorDidMount: (editor: any) => void; footerItems?: { - start?: Array; - end?: Array; + start?: any[]; + end?: any[]; }; headerRef?: React.RefObject; provideCompletionItems: monaco.languages.CompletionItemProvider['provideCompletionItems']; @@ -72,28 +67,23 @@ export const DefaultInput: React.FC = ({ }} /> {footerItems && ( -
- {footerItems.start?.map((item, index) => ( - - ))} -
- {footerItems.end?.map((item, index) => ( - - ))} -
+ + + {footerItems.start?.map((item) => ( + + {item} + + ))} + + + {footerItems.end?.map((item) => ( + {item} + ))} + + )}
); }; -const FooterItem: React.FC<{ item: FooterItem | string }> = ({ item }) => { - const color = typeof item === 'string' ? ('subdued' as const) : item.color; - const text = typeof item === 'string' ? item : item.text; - return ( - - {text} - - ); -}; - export const createDefaultEditor = createEditor(SingleLineInput, null, DefaultInput); diff --git a/src/plugins/data/public/ui/query_editor/editors/shared.tsx b/src/plugins/data/public/ui/query_editor/editors/shared.tsx index 23b46c22a48c..ad9af1e87e19 100644 --- a/src/plugins/data/public/ui/query_editor/editors/shared.tsx +++ b/src/plugins/data/public/ui/query_editor/editors/shared.tsx @@ -4,6 +4,7 @@ */ import React from 'react'; +import { EuiCompressedFieldText } from '@elastic/eui'; import { monaco } from '@osd/monaco'; import { CodeEditor } from '../../../../../opensearch_dashboards_react/public'; @@ -13,6 +14,7 @@ interface SingleLineInputProps extends React.JSX.IntrinsicAttributes { onChange: (value: string) => void; editorDidMount: (editor: any) => void; provideCompletionItems: monaco.languages.CompletionItemProvider['provideCompletionItems']; + prepend?: React.ComponentProps['prepend']; } type CollapsedComponent = React.ComponentType; @@ -63,51 +65,55 @@ export const SingleLineInput: React.FC = ({ onChange, editorDidMount, provideCompletionItems, + prepend, }) => ( -
- + {prepend} +
+ + overviewRulerLanes: 0, + hideCursorInOverviewRuler: true, + cursorStyle: 'line', + wordBasedSuggestions: false, + }} + suggestionProvider={{ + provideCompletionItems, + }} + languageConfiguration={{ + autoClosingPairs: [ + { + open: '(', + close: ')', + }, + { + open: '"', + close: '"', + }, + ], + }} + /> +
); diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index ccc616911ed8..619184883220 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { PopoverAnchorPosition } from '@elastic/eui'; +import { EuiCompressedFieldText, EuiText, PopoverAnchorPosition } from '@elastic/eui'; import classNames from 'classnames'; import { isEqual } from 'lodash'; import React, { Component, createRef, RefObject } from 'react'; @@ -15,9 +15,11 @@ import { fromUser, getQueryLog, PersistedLog, toUser } from '../../query'; import { SuggestionsListSize } from '../typeahead/suggestions_component'; import { QueryLanguageSelector } from './language_selector'; import { QueryEditorExtensions } from './query_editor_extensions'; -import { QueryEditorBtnCollapse } from './query_editor_btn_collapse'; import { getQueryService, getIndexPatterns } from '../../services'; import { DatasetSelector } from '../dataset_selector'; +import { QueryControls } from '../../query/query_string/language_service/get_query_control_links'; +import { RecentQuery } from '../../query/query_string/language_service/recent_query'; +import { DefaultInputProps } from './editors'; const LANGUAGE_ID_SQL = 'SQL'; monaco.languages.register({ id: LANGUAGE_ID_SQL }); @@ -46,6 +48,8 @@ export interface QueryEditorProps { bannerClassName?: string; footerClassName?: string; filterBar?: any; + prepend?: React.ComponentProps['prepend']; + savedQueryManagement?: any; } interface Props extends QueryEditorProps { @@ -157,6 +161,10 @@ export default class QueryEditorUI extends Component { }); }; + private onClickRecentQuery = (query: Query, timeRange?: TimeRange) => { + this.onSubmit(query, timeRange); + }; + private onInputChange = (value: string) => { this.onQueryStringChange(value); @@ -285,6 +293,21 @@ export default class QueryEditorUI extends Component { }; }; + public onToggleCollapse = () => { + this.setState({ isCollapsed: !this.state.isCollapsed }); + }; + + private renderQueryControls = () => { + return ( + + ); + }; + public render() { const className = classNames(this.props.className); @@ -305,7 +328,7 @@ export default class QueryEditorUI extends Component { value: this.getQueryString(), }; - const defaultInputProps = { + const defaultInputProps: DefaultInputProps = { ...baseInputProps, onChange: this.onInputChange, editorDidMount: (editor: monaco.editor.IStandaloneCodeEditor) => { @@ -315,8 +338,19 @@ export default class QueryEditorUI extends Component { }, footerItems: { start: [ - `${this.state.lineCount} ${this.state.lineCount === 1 ? 'line' : 'lines'}`, - this.props.query.dataset?.timeFieldName || '', + + {`${this.state.lineCount} ${this.state.lineCount === 1 ? 'line' : 'lines'}`} + , + + {this.props.query.dataset?.timeFieldName || ''} + , + ], + end: [ + , ], }, provideCompletionItems: this.provideCompletionItems, @@ -350,6 +384,7 @@ export default class QueryEditorUI extends Component { }; }, provideCompletionItems: this.provideCompletionItems, + prepend: this.props.prepend, }; const languageEditorFunc = this.languageManager.getLanguage(this.props.query.language)!.editor; @@ -374,10 +409,6 @@ export default class QueryEditorUI extends Component { className={classNames('osdQueryEditor__banner', this.props.bannerClassName)} />
- this.setState({ isCollapsed: !this.state.isCollapsed })} - isCollapsed={!this.state.isCollapsed} - />
{this.state.isCollapsed @@ -385,7 +416,7 @@ export default class QueryEditorUI extends Component { : languageEditor.TopBar.Expanded && languageEditor.TopBar.Expanded()}
{languageSelector} - {this.props.queryActions} +
{this.renderQueryControls()}
void; - isCollapsed: boolean; -} - -export function QueryEditorBtnCollapse({ onClick, isCollapsed }: Props) { - const label = i18n.translate('queryEditor.collapse', { - defaultMessage: 'Toggle query editor', - }); - return ( -
- - - -
- ); -} diff --git a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx index 0c15a551a3f8..a5248d3d61cb 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor_top_row.tsx @@ -53,6 +53,7 @@ export interface QueryEditorTopRowProps { timeHistory?: TimeHistoryContract; indicateNoData?: boolean; datePickerRef?: React.RefObject; + savedQueryManagement?: any; } // Needed for React.lazy @@ -174,7 +175,7 @@ export default function QueryEditorTopRow(props: QueryEditorTopRowProps) { ); diff --git a/src/plugins/data/public/ui/search_bar/search_bar.tsx b/src/plugins/data/public/ui/search_bar/search_bar.tsx index 891cf70379b2..b986a1e11ddd 100644 --- a/src/plugins/data/public/ui/search_bar/search_bar.tsx +++ b/src/plugins/data/public/ui/search_bar/search_bar.tsx @@ -234,19 +234,22 @@ class SearchBarUI extends Component { return this.props.showQueryBar && (showDatePicker || showQueryInput); } - private shouldRenderFilterBar(isEnhancementsEnabledOverride: boolean) { - const language = this.queryStringManager - .getLanguageService() - .getLanguage(this.state.query?.language!); - const isFilterable = language?.fields?.filterable !== false; // Render if undefined or true + private isQueryLanguageFilterable() { + return ( + this.queryStringManager.getLanguageService().getLanguage(this.state.query?.language!)?.fields + ?.filterable ?? true // Render if undefined or true + ); + } + private shouldRenderFilterBar(isEnhancementsEnabledOverride: boolean) { return ( this.props.showFilterBar && this.props.filters && (!this.useNewHeader || this.props.filters.length > 0) && this.props.indexPatterns && compact(this.props.indexPatterns).length > 0 && - (!isEnhancementsEnabledOverride || (isEnhancementsEnabledOverride && isFilterable)) + (!isEnhancementsEnabledOverride || + (isEnhancementsEnabledOverride && this.isQueryLanguageFilterable)) ); } @@ -380,10 +383,9 @@ class SearchBarUI extends Component { } } ); - const dataset = this.queryStringManager.getQuery().dataset; - if (dataset && queryAndDateRange.query) { + + if (queryAndDateRange.query) { this.queryStringManager.addToQueryHistory( - dataset, queryAndDateRange.query, queryAndDateRange.dateRange ); @@ -427,7 +429,10 @@ class SearchBarUI extends Component { .getLanguage(this.state.query?.language!) ?.editorSupportedAppNames?.includes(this.services.appName); - const searchBarMenu = (useSaveQueryMenu: boolean = false) => { + const searchBarMenu = ( + useSaveQueryMenu: boolean = false, + isQueryEditorControl: boolean = false + ) => { return ( this.state.query && this.props.onClearSavedQuery && ( @@ -444,6 +449,7 @@ class SearchBarUI extends Component { savedQueryService={this.savedQueryService} onClearSavedQuery={this.props.onClearSavedQuery} useSaveQueryMenu={useSaveQueryMenu} + isQueryEditorControl={isQueryEditorControl} /> ) ); @@ -480,6 +486,7 @@ class SearchBarUI extends Component { } let queryBar; + if (this.shouldRenderQueryBar(isEnhancementsEnabledOverride)) { queryBar = ( { onSubmit={this.onQueryBarSubmit} indexPatterns={this.props.indexPatterns} isLoading={this.props.isLoading} - prepend={this.props.showFilterBar ? searchBarMenu(!this.useNewHeader) : undefined} + prepend={this.props.showFilterBar ? searchBarMenu(!this.useNewHeader, false) : undefined} showDatePicker={this.props.showDatePicker} dateRangeFrom={this.state.dateRangeFrom} dateRangeTo={this.state.dateRangeTo} @@ -521,7 +528,7 @@ class SearchBarUI extends Component { onSubmit={this.onQueryBarSubmit} indexPatterns={this.props.indexPatterns} isLoading={this.props.isLoading} - prepend={this.props.showFilterBar ? searchBarMenu(!this.useNewHeader) : undefined} + prepend={this.isQueryLanguageFilterable() ? searchBarMenu() : undefined} showDatePicker={this.props.showDatePicker} dateRangeFrom={this.state.dateRangeFrom} dateRangeTo={this.state.dateRangeTo} @@ -540,6 +547,7 @@ class SearchBarUI extends Component { dataTestSubj={this.props.dataTestSubj} indicateNoData={this.props.indicateNoData} datePickerRef={this.props.datePickerRef} + savedQueryManagement={searchBarMenu(false, true)} /> ); } From e8683cafb9f0f1d6e2c7124f688f514c183e05aa Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:12:47 -0700 Subject: [PATCH 254/276] fix(queryAssist): allow dataset with `DATA_SOURCE` type (#7890) (#7892) * fix(queryAssist): allow dataset with DATA_SOURCE type * prevent multiple calls to get available languages --------- (cherry picked from commit 8033aa457d263b4ece3b8d9fa6ae86f2f016799c) Signed-off-by: Joshua Li Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../query_assist/utils/create_extension.tsx | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx index bebe250a91ce..ac56f35a7281 100644 --- a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx +++ b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx @@ -22,15 +22,25 @@ import assistantMark from '../../assets/query_assist_mark.svg'; */ const getAvailableLanguagesForDataSource = (() => { const availableLanguagesByDataSource: Map = new Map(); + const pendingRequests: Map> = new Map(); + return async (http: HttpSetup, dataSourceId: string | undefined) => { const cached = availableLanguagesByDataSource.get(dataSourceId); if (cached !== undefined) return cached; - const languages = await http + + const pendingRequest = pendingRequests.get(dataSourceId); + if (pendingRequest !== undefined) return pendingRequest; + + const languagesPromise = http .get<{ configuredLanguages: string[] }>(API.QUERY_ASSIST.LANGUAGES, { query: { dataSourceId }, }) .then((response) => response.configuredLanguages) - .catch(() => []); + .catch(() => []) + .finally(() => pendingRequests.delete(dataSourceId)); + pendingRequests.set(dataSourceId, languagesPromise); + + const languages = await languagesPromise; availableLanguagesByDataSource.set(dataSourceId, languages); return languages; }; @@ -47,7 +57,11 @@ const getAvailableLanguages$ = (http: HttpSetup, data: DataPublicPluginSetup) => switchMap(async (query) => { // currently query assist tool relies on opensearch API to get index // mappings, external data source types (e.g. s3) are not supported - if (query.dataset?.dataSource?.type !== DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH) return []; + if ( + query.dataset?.dataSource?.type !== DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH && + query.dataset?.dataSource?.type !== 'DATA_SOURCE' + ) + return []; const dataSourceId = query.dataset?.dataSource?.id; return getAvailableLanguagesForDataSource(http, dataSourceId); From 4ea3746ee1a4a21b0b9a70c29cbdc123651a1cf7 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 15:19:22 -0700 Subject: [PATCH 255/276] [Discover 2.0] UI Fixes (#7885) (#7893) * [Discover 2.0] UI Fixes * minor fixes * fix test failures * fix test * fix bootstrap --------- (cherry picked from commit eefbdfd26f45a247cd85f3c4bc39d4ca1ea1a190) Signed-off-by: Ashwin P Chandran Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- docs/openapi/README.md | 7 +- .../public/overlays/modal/modal_service.tsx | 4 +- .../_dataset_configurator.scss | 3 + .../dataset_selector/_dataset_selector.scss | 13 ++++ .../public/ui/dataset_selector/_index.scss | 1 + .../ui/dataset_selector/configurator.tsx | 2 +- .../ui/dataset_selector/dataset_explorer.tsx | 3 +- .../ui/dataset_selector/dataset_selector.tsx | 71 +++++++++++-------- .../public/ui/query_editor/_query_editor.scss | 1 - .../default_editor/_default_editor.scss | 25 ++----- .../editors/default_editor/index.tsx | 19 ++--- .../public/ui/query_editor/editors/shared.tsx | 2 +- 12 files changed, 86 insertions(+), 65 deletions(-) create mode 100644 src/plugins/data/public/ui/dataset_selector/_dataset_configurator.scss diff --git a/docs/openapi/README.md b/docs/openapi/README.md index a19b2a9a830a..92779f2220b1 100644 --- a/docs/openapi/README.md +++ b/docs/openapi/README.md @@ -6,4 +6,9 @@ The OpenAPI (https://swagger.io/specification/) Specification defines a standard When generated, OpenAPI definition can then be used by documentation generation tools to display the API such as swagger UI, code generation tools to generate servers and clients in various programming languages, testing tools, and many other use cases. ### Starting Up the Swagger UI Locally -To start up the swagger UI locally for development or validation purposes, you can simply start a server in the directory where the index.html file is located. `npx serve` is a simple way to start a server. \ No newline at end of file +To start up the swagger UI locally for development or validation purposes, you can simply start a server in the directory where the index.html file is located. `npx serve` is a simple way to start a server. + +### API Docs + +- [Saved Objects](https://opensearch-project.github.io/OpenSearch-Dashboards/docs/openapi/saved_objects/) +- [Index Patterns](https://opensearch-project.github.io/OpenSearch-Dashboards/docs/openapi/index_patterns/)https://github.com/ashwin-pc/OpenSearch-Dashboards/blob/26b8c38cf4b9f6cf9a809dad370d26cf37b72571/docs/openapi/README.md \ No newline at end of file diff --git a/src/core/public/overlays/modal/modal_service.tsx b/src/core/public/overlays/modal/modal_service.tsx index a1f7a7e59cdb..e14f09eac2db 100644 --- a/src/core/public/overlays/modal/modal_service.tsx +++ b/src/core/public/overlays/modal/modal_service.tsx @@ -31,7 +31,7 @@ /* eslint-disable max-classes-per-file */ import { i18n as t } from '@osd/i18n'; -import { EuiModal, EuiConfirmModal, EuiConfirmModalProps } from '@elastic/eui'; +import { EuiModal, EuiConfirmModal, EuiConfirmModalProps, EuiModalProps } from '@elastic/eui'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subject } from 'rxjs'; @@ -111,7 +111,7 @@ export interface OverlayModalStart { /** * @public */ -export interface OverlayModalOpenOptions { +export interface OverlayModalOpenOptions extends Pick { className?: string; closeButtonAriaLabel?: string; 'data-test-subj'?: string; diff --git a/src/plugins/data/public/ui/dataset_selector/_dataset_configurator.scss b/src/plugins/data/public/ui/dataset_selector/_dataset_configurator.scss new file mode 100644 index 000000000000..44e89b19ffb3 --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/_dataset_configurator.scss @@ -0,0 +1,3 @@ +.datasetConfigurator { + height: 600px; +} diff --git a/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss b/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss index 9ec6ca531cf8..ea780f1c22e8 100644 --- a/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss +++ b/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss @@ -11,4 +11,17 @@ width: 365px; padding: $euiSizeXS; } + + &__footer { + padding: $euiSizeXS; + } + + &__advancedModal { + width: 1200px; + } + + &__checkbox { + flex: 1; + align-self: center; + } } diff --git a/src/plugins/data/public/ui/dataset_selector/_index.scss b/src/plugins/data/public/ui/dataset_selector/_index.scss index b1d4dbe34c68..a16a39a501c7 100644 --- a/src/plugins/data/public/ui/dataset_selector/_index.scss +++ b/src/plugins/data/public/ui/dataset_selector/_index.scss @@ -1,2 +1,3 @@ @import "./dataset_explorer"; @import "./dataset_selector"; +@import "./dataset_configurator"; diff --git a/src/plugins/data/public/ui/dataset_selector/configurator.tsx b/src/plugins/data/public/ui/dataset_selector/configurator.tsx index 32e48691aa87..e59683dffa28 100644 --- a/src/plugins/data/public/ui/dataset_selector/configurator.tsx +++ b/src/plugins/data/public/ui/dataset_selector/configurator.tsx @@ -79,7 +79,7 @@ export const Configurator = ({ - + {(list, search) => ( @@ -182,7 +183,7 @@ const LoadingEmptyColumn = ({ isLoading }: { isLoading: boolean }) =>

...

- + {(list) => <>{list}}
diff --git a/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx b/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx index ed0bd76fdaf1..0a251a8dfe3e 100644 --- a/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx +++ b/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx @@ -3,12 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useEffect, useMemo, useState, useCallback } from 'react'; +import React, { useEffect, useMemo, useState, useCallback, useRef } from 'react'; import { + EuiButton, EuiButtonEmpty, EuiIcon, EuiPopover, - EuiPopoverTitle, + EuiPopoverFooter, EuiSelectable, EuiSelectableOption, EuiToolTip, @@ -35,6 +36,14 @@ export const DatasetSelector = ({ const [datasets, setDatasets] = useState([]); const { overlays, savedObjects } = services; + const isMounted = useRef(true); + + useEffect(() => { + return () => { + isMounted.current = false; + }; + }, []); + const datasetService = getQueryService().queryString.getDatasetService(); const datasetIcon = @@ -46,6 +55,8 @@ export const DatasetSelector = ({ const fetchedIndexPatternDataStructures = await typeConfig.fetch(savedObjects.client, []); + if (!isMounted.current) return; + const fetchedDatasets = fetchedIndexPatternDataStructures.children?.map((pattern) => typeConfig.toDataset([pattern]) @@ -139,13 +150,33 @@ export const DatasetSelector = ({ display="block" panelPaddingSize="none" > - - + {(list, search) => ( + <> + {search} + {list} + + )} + + + { closePopover(); @@ -161,7 +192,11 @@ export const DatasetSelector = ({ }} onCancel={() => overlay?.close()} /> - ) + ), + { + maxWidth: false, + className: 'datasetSelector__advancedModal', + } ); }} > @@ -169,28 +204,8 @@ export const DatasetSelector = ({ id="data.datasetSelector.advancedButton" defaultMessage="View all available data" /> - - - - {(list, search) => ( - <> - {search} - {list} - - )} - + +
); }; diff --git a/src/plugins/data/public/ui/query_editor/_query_editor.scss b/src/plugins/data/public/ui/query_editor/_query_editor.scss index 626cc4a3d2b4..7edfebfed938 100644 --- a/src/plugins/data/public/ui/query_editor/_query_editor.scss +++ b/src/plugins/data/public/ui/query_editor/_query_editor.scss @@ -193,7 +193,6 @@ .osdQuerEditor__singleLine { padding: $euiSizeS; background-color: $euiColorEmptyShade; - border: $euiBorderThin; .monaco-editor .view-overlays .current-line { border: none; diff --git a/src/plugins/data/public/ui/query_editor/editors/default_editor/_default_editor.scss b/src/plugins/data/public/ui/query_editor/editors/default_editor/_default_editor.scss index a5897c0b6fb9..ccebd35c4ead 100644 --- a/src/plugins/data/public/ui/query_editor/editors/default_editor/_default_editor.scss +++ b/src/plugins/data/public/ui/query_editor/editors/default_editor/_default_editor.scss @@ -1,26 +1,9 @@ -.defaultEditor__footer { - display: flex; - align-items: center; - flex-wrap: nowrap; - background-color: $euiColorLightestShade; - gap: $euiSizeS; - margin-top: 1px; - margin-left: $euiSizeS; - margin-right: $euiSizeS; - - .defaultEditor__footerItem { - padding: 0 $euiSizeXS; - display: flex; - align-items: center; - } - - .defaultEditor__footerItem__end { - justify-content: flex-end; - } -} - .defaultEditor { border: $euiBorderThin; border-radius: $euiSizeXS; margin: 0 $euiSizeXS $euiSizeXS; + + &__footer { + margin-left: $euiSizeXS; + } } diff --git a/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx b/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx index 7d52dd55607e..b7bb11c18a8d 100644 --- a/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx +++ b/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx @@ -66,22 +66,23 @@ export const DefaultInput: React.FC = ({ ], }} /> - {footerItems && ( - - +
+ {footerItems && ( + {footerItems.start?.map((item) => ( - + {item} ))} - - + {footerItems.end?.map((item) => ( - {item} + + {item} + ))} - - )} + )} +
); }; diff --git a/src/plugins/data/public/ui/query_editor/editors/shared.tsx b/src/plugins/data/public/ui/query_editor/editors/shared.tsx index ad9af1e87e19..1da3b2c880c3 100644 --- a/src/plugins/data/public/ui/query_editor/editors/shared.tsx +++ b/src/plugins/data/public/ui/query_editor/editors/shared.tsx @@ -67,7 +67,7 @@ export const SingleLineInput: React.FC = ({ provideCompletionItems, prepend, }) => ( -
+
{prepend}
Date: Wed, 28 Aug 2024 15:23:55 -0700 Subject: [PATCH 256/276] [Auto Suggest] DQL Updates (#7593) (#7869) Update to DQL Autocomplete: https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7391 Every file removal under `grammar/.antlr` can be ignored. - [x] use official value suggestion methods instead of direct api call - [x] removed language specified configuration - [ ] ~~added memoization for value suggestion to reduce number of calls made~~ - [x] removed core start from query suggestion function - [x] added tests for value suggestion - [x] added more test coverage for other general cases - [ ] ~~[[RFC] Monaco Code Editor provider registration #7594](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/7594) made changes based on this RFC~~ - [x] remove grammar/.antlr auto generated files - [x] updated types in code completion and related files - [x] fixed many group value suggestion bugs and edge cases with more robust parser visitor - [x] fix group value NOT suggestion bugs - [ ] ~~added basic keyword syntax highlighting~~ --------- (cherry picked from commit 741c0d691c5e0f4455ff6ced0875a34f3d6db3ed) Signed-off-by: Paul Sebastian Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- .gitignore | 3 +- changelogs/fragments/7593.yml | 2 + .../public/antlr/dql/code_completion.test.ts | 433 ++++++++- .../data/public/antlr/dql/code_completion.ts | 216 +++-- .../antlr/dql/grammar/.antlr/DQLLexer.interp | 56 -- .../antlr/dql/grammar/.antlr/DQLLexer.java | 166 ---- .../antlr/dql/grammar/.antlr/DQLLexer.tokens | 20 - .../antlr/dql/grammar/.antlr/DQLParser.interp | 50 -- .../antlr/dql/grammar/.antlr/DQLParser.java | 828 ------------------ .../antlr/dql/grammar/.antlr/DQLParser.tokens | 20 - .../data/public/antlr/shared/constants.ts | 192 ---- .../autocomplete/autocomplete_service.ts | 6 +- .../providers/query_suggestion_provider.ts | 4 +- .../query_string_input/query_string_input.tsx | 4 +- .../public/code_editor/code_editor.tsx | 32 +- 15 files changed, 571 insertions(+), 1461 deletions(-) create mode 100644 changelogs/fragments/7593.yml delete mode 100644 src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.interp delete mode 100644 src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.java delete mode 100644 src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.tokens delete mode 100644 src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.interp delete mode 100644 src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.java delete mode 100644 src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.tokens delete mode 100644 src/plugins/data/public/antlr/shared/constants.ts diff --git a/.gitignore b/.gitignore index 99457f958f5b..c530adedb7bb 100644 --- a/.gitignore +++ b/.gitignore @@ -70,4 +70,5 @@ snapshots.js .yarn-local-mirror # Ignore the generated antlr files -/src/plugins/data/public/antlr/opensearch_sql/grammar/.antlr \ No newline at end of file +/src/plugins/data/public/antlr/opensearch_sql/grammar/.antlr +/src/plugins/data/public/antlr/dql/grammar/.antlr \ No newline at end of file diff --git a/changelogs/fragments/7593.yml b/changelogs/fragments/7593.yml new file mode 100644 index 000000000000..d08a386a3978 --- /dev/null +++ b/changelogs/fragments/7593.yml @@ -0,0 +1,2 @@ +fix: +- Update DQL Autocomplete in code and functionality ([#7593](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7593)) \ No newline at end of file diff --git a/src/plugins/data/public/antlr/dql/code_completion.test.ts b/src/plugins/data/public/antlr/dql/code_completion.test.ts index d8f75ebf0e1c..583976126965 100644 --- a/src/plugins/data/public/antlr/dql/code_completion.test.ts +++ b/src/plugins/data/public/antlr/dql/code_completion.test.ts @@ -5,12 +5,241 @@ import { monaco } from '@osd/monaco'; import { getSuggestions } from './code_completion'; -import { - booleanOperatorSuggestions, - fieldNameWithNotSuggestions, - notOperatorSuggestion, - testingIndex, -} from '../shared/constants'; +import { DataPublicPluginStart, IDataPluginServices } from '../../types'; +import { IndexPattern } from '../../index_patterns'; + +/** + * Constants + */ + +const testingIndex = ({ + title: 'opensearch_dashboards_sample_data_flights', + fields: [ + { + count: 0, + name: 'Carrier', + displayName: 'Carrier', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: undefined, + }, + { + count: 2, + name: 'DestCityName', + displayName: 'DestCityName', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: undefined, + }, + { + count: 0, + name: 'DestCountry', + displayName: 'DestCountry', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: undefined, + }, + { + count: 0, + name: 'DestWeather', + displayName: 'DestWeather', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: undefined, + }, + { + count: 0, + name: 'DistanceMiles', + displayName: 'DistanceMiles', + type: 'number', + esTypes: ['float'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: undefined, + }, + { + count: 0, + name: 'FlightDelay', + displayName: 'FlightDelay', + type: 'boolean', + esTypes: ['boolean'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: undefined, + }, + { + count: 0, + name: 'FlightNum', + displayName: 'FlightNum', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: undefined, + }, + { + count: 0, + name: 'OriginWeather', + displayName: 'OriginWeather', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: undefined, + }, + { + count: 0, + name: '_id', + displayName: '_id', + type: 'string', + esTypes: ['_id'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + subType: undefined, + }, + { + count: 0, + name: '_index', + displayName: '_index', + type: 'string', + esTypes: ['_index'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + subType: undefined, + }, + { + count: 0, + name: '_score', + displayName: '_score', + type: 'number', + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + subType: undefined, + }, + { + count: 0, + name: '_source', + displayName: '_source', + type: '_source', + esTypes: ['_source'], + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + subType: undefined, + }, + { + count: 0, + name: '_type', + displayName: '_type', + type: 'string', + esTypes: ['_type'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + subType: undefined, + }, + ], +} as unknown) as IndexPattern; + +const booleanOperatorSuggestions = [ + { end: -1, start: -1, text: 'or', type: 17 }, + { end: -1, start: -1, text: 'and', type: 17 }, +]; + +const notOperatorSuggestion = { text: 'not', type: 17, end: -1, start: -1 }; + +const fieldNameSuggestions: Array<{ + text: string; + type: number; + insertText?: string; + end: number; + start: number; +}> = [ + { text: 'Carrier', type: 3, insertText: 'Carrier: ', end: -1, start: -1 }, + { text: 'DestCityName', type: 3, insertText: 'DestCityName: ', end: -1, start: -1 }, + { text: 'DestCountry', type: 3, insertText: 'DestCountry: ', end: -1, start: -1 }, + { text: 'DestWeather', type: 3, insertText: 'DestWeather: ', end: -1, start: -1 }, + { text: 'DistanceMiles', type: 3, insertText: 'DistanceMiles: ', end: -1, start: -1 }, + { text: 'FlightDelay', type: 3, insertText: 'FlightDelay: ', end: -1, start: -1 }, + { text: 'FlightNum', type: 3, insertText: 'FlightNum: ', end: -1, start: -1 }, + { text: 'OriginWeather', type: 3, insertText: 'OriginWeather: ', end: -1, start: -1 }, + { text: '_id', type: 3, insertText: '_id: ', end: -1, start: -1 }, + { text: '_index', type: 3, insertText: '_index: ', end: -1, start: -1 }, + { text: '_score', type: 3, insertText: '_score: ', end: -1, start: -1 }, + { text: '_source', type: 3, insertText: '_source: ', end: -1, start: -1 }, + { text: '_type', type: 3, insertText: '_type: ', end: -1, start: -1 }, +]; + +const fieldNameWithNotSuggestions = fieldNameSuggestions.concat(notOperatorSuggestion); + +const carrierValues = [ + 'Logstash Airways', + 'BeatsWest', + 'OpenSearch Dashboards Airlines', + 'OpenSearch-Air', +]; + +const allCarrierValueSuggestions = [ + { text: 'Logstash Airways', type: 13, start: -1, end: -1 }, + { text: 'BeatsWest', type: 13, start: -1, end: -1 }, + { + text: 'OpenSearch Dashboards Airlines', + type: 13, + start: -1, + end: -1, + }, + { text: 'OpenSearch-Air', type: 13, start: -1, end: -1 }, +]; + +const carrierWithNotSuggestions = allCarrierValueSuggestions.concat(notOperatorSuggestion); + +const logCarrierValueSuggestion = [{ text: 'Logstash Airways', type: 13, start: -1, end: -1 }]; + +const openCarrierValueSuggestion = [ + { + text: 'OpenSearch Dashboards Airlines', + type: 13, + start: -1, + end: -1, + }, + { text: 'OpenSearch-Air', type: 13, start: -1, end: -1 }, +]; + +/** + * Actual Tests + */ jest.mock('../../services', () => ({ getUiService: () => ({ @@ -20,6 +249,14 @@ jest.mock('../../services', () => ({ }), })); +const mockValueSuggestions = jest.fn((passedin) => { + const { field, query } = passedin; + if (field?.name === 'Carrier') { + return carrierValues.filter((val) => val.startsWith(query)); + } + return []; +}); + const getSuggestionsAtPos = async (query: string, endPos: number) => { return await getSuggestions({ query, @@ -28,47 +265,84 @@ const getSuggestionsAtPos = async (query: string, endPos: number) => { language: '', // not relevant selectionEnd: 0, // not relevant selectionStart: 0, // not relevant - services: { appName: 'discover' }, + services: { + appName: 'discover', + data: ({ + autocomplete: { getValueSuggestions: mockValueSuggestions }, + } as unknown) as DataPublicPluginStart, + } as IDataPluginServices, }); }; -const getSuggestionAtEnd = async (query: string) => { +const getSuggestionsAtEnd = async (query: string) => { return await getSuggestionsAtPos(query, query.length + 1); }; +const testAroundClosing = ( + query: string, + surroundingChars: Array, + testName: string, + expectedValue: any, + includeBase?: boolean +) => { + if (includeBase) { + it(testName, async () => { + expect(await getSuggestionsAtEnd(query)).toStrictEqual(expectedValue); + }); + } + + let currQuery = query; + if (surroundingChars[0]) { + it(testName + ' - opened', async () => { + currQuery = currQuery + surroundingChars[0]; + expect(await getSuggestionsAtEnd(currQuery)).toStrictEqual(expectedValue); + }); + } + + it(testName + ' - closed', async () => { + currQuery = currQuery + surroundingChars[1]; + expect(await getSuggestionsAtPos(currQuery, currQuery.length)).toStrictEqual(expectedValue); + }); + + // TODO: besides NOT issue, need to consolidate behavior where there is no val vs w/ val + it.skip(testName + ' - no suggestion after closing', async () => { + expect(await getSuggestionsAtEnd(currQuery)).toStrictEqual([]); + }); +}; + describe('Test Boolean Operators', () => { it('should suggest AND and OR after expression', async () => { - expect(await getSuggestionAtEnd('field: value ')).toStrictEqual(booleanOperatorSuggestions); + expect(await getSuggestionsAtEnd('field: value ')).toStrictEqual(booleanOperatorSuggestions); }); it('should suggest NOT initially', async () => { - expect(await getSuggestionAtEnd('')).toContainEqual(notOperatorSuggestion); + expect(await getSuggestionsAtEnd('')).toContainEqual(notOperatorSuggestion); }); it('should suggest NOT after expression', async () => { - expect(await getSuggestionAtEnd('field: value and ')).toContainEqual(notOperatorSuggestion); + expect(await getSuggestionsAtEnd('field: value and ')).toContainEqual(notOperatorSuggestion); }); it('should not suggest NOT twice', async () => { - expect(await getSuggestionAtEnd('not ')).not.toContainEqual(notOperatorSuggestion); + expect(await getSuggestionsAtEnd('not ')).not.toContainEqual(notOperatorSuggestion); }); it('should suggest after multiple token search', async () => { - expect(await getSuggestionAtEnd('field: one two three ')).toStrictEqual( + expect(await getSuggestionsAtEnd('field: one two three ')).toStrictEqual( booleanOperatorSuggestions ); }); it('should suggest after phrase value', async () => { - expect(await getSuggestionAtEnd('field: "value" ')).toStrictEqual(booleanOperatorSuggestions); + expect(await getSuggestionsAtEnd('field: "value" ')).toStrictEqual(booleanOperatorSuggestions); }); it('should suggest after number', async () => { - expect(await getSuggestionAtEnd('field: 123 ')).toStrictEqual(booleanOperatorSuggestions); + expect(await getSuggestionsAtEnd('field: 123 ')).toStrictEqual(booleanOperatorSuggestions); }); it('should not suggest after incomplete quote', async () => { - expect(await getSuggestionAtEnd('field: "value ')).not.toStrictEqual( + expect(await getSuggestionsAtEnd('field: "value ')).not.toStrictEqual( booleanOperatorSuggestions ); }); @@ -76,15 +350,15 @@ describe('Test Boolean Operators', () => { describe('Test Boolean Operators within groups', () => { it('should suggest AND and OR', async () => { - expect(await getSuggestionAtEnd('field: (value ')).toStrictEqual(booleanOperatorSuggestions); + expect(await getSuggestionsAtEnd('field: (value ')).toStrictEqual(booleanOperatorSuggestions); }); it('should suggest NOT after expression', async () => { - expect(await getSuggestionAtEnd('field: (value and ')).toContainEqual(notOperatorSuggestion); + expect(await getSuggestionsAtEnd('field: (value and ')).toContainEqual(notOperatorSuggestion); }); it('should suggest operator within nested group', async () => { - expect(await getSuggestionAtEnd('field: ("one" and ("two" ')).toStrictEqual( + expect(await getSuggestionsAtEnd('field: ("one" and ("two" ')).toStrictEqual( booleanOperatorSuggestions ); }); @@ -92,18 +366,133 @@ describe('Test Boolean Operators within groups', () => { describe('Test field suggestions', () => { it('basic field suggestion', async () => { - expect(await getSuggestionAtEnd('')).toStrictEqual(fieldNameWithNotSuggestions); + expect(await getSuggestionsAtEnd('')).toStrictEqual(fieldNameWithNotSuggestions); }); it('field suggestion after one term', async () => { - expect(await getSuggestionAtEnd('field: value and ')).toStrictEqual( + expect(await getSuggestionsAtEnd('field: value and ')).toStrictEqual( fieldNameWithNotSuggestions ); }); it('field suggestion within group', async () => { - expect(await getSuggestionAtEnd('field: value and (one: "two" or ')).toStrictEqual( + expect(await getSuggestionsAtEnd('field: value and (one: "two" or ')).toStrictEqual( fieldNameWithNotSuggestions ); }); }); + +describe('Test basic value suggestions', () => { + it('do not suggest unknown field', async () => { + expect(await getSuggestionsAtEnd('field: ')).toStrictEqual([]); + }); + + it('suggest token search value for field', async () => { + expect(await getSuggestionsAtEnd('Carrier: ')).toStrictEqual(allCarrierValueSuggestions); + }); + + it('suggest value for field without surrounding space', async () => { + expect(await getSuggestionsAtEnd('Carrier:')).toStrictEqual(allCarrierValueSuggestions); + }); + + it('suggest value from partial value', async () => { + expect(await getSuggestionsAtEnd('Carrier: Log')).toStrictEqual(logCarrierValueSuggestion); + }); + + it('suggest multiple values from partial value', async () => { + expect(await getSuggestionsAtEnd('Carrier: Open')).toStrictEqual(openCarrierValueSuggestion); + }); + + testAroundClosing( + 'Carrier: ', + ['"', '"'], + 'should suggest within phrase', + allCarrierValueSuggestions + ); + + it('suggest rest of partial value within quotes', async () => { + const query = 'Carrier: "OpenSearch"'; + expect(await getSuggestionsAtPos(query, query.length)).toStrictEqual( + openCarrierValueSuggestion + ); + }); + + // it('should suggest within multiple token search context'); <-- maybe it means suggest either bool OR next partial value +}); + +describe('Test value suggestion with multiple terms', () => { + testAroundClosing( + 'Carrier: BeatsWest or Carrier: ', + ['"', '"'], + 'should suggest after one field value expression', + allCarrierValueSuggestions, + true + ); + + it('should suggest after field value expression and partial value', async () => { + expect(await getSuggestionsAtEnd('Carrier: BeatsWest or Carrier: Open')).toStrictEqual( + openCarrierValueSuggestion + ); + }); + + testAroundClosing( + 'Carrier: BeatsWest or Carrier: "Open', + [undefined, '"'], + 'should suggest after field value expression in partial value quotes', + openCarrierValueSuggestion, + true + ); +}); + +describe('Test group value suggestions', () => { + testAroundClosing( + 'Carrier: ', + ['(', ')'], + 'should suggest within grouping', + carrierWithNotSuggestions + ); + + testAroundClosing( + 'Carrier: (', + ['"', '"'], + 'should suggest within grouping and phrase', + allCarrierValueSuggestions + ); + + testAroundClosing( + 'Carrier: ("', + [undefined, '")'], + 'should suggest within closed grouping and phrase', + allCarrierValueSuggestions + ); + + testAroundClosing( + 'Carrier: (BeatsWest or ', + [undefined, ')'], + 'should suggest after grouping with term', + carrierWithNotSuggestions, + true + ); + + testAroundClosing( + 'Carrier: (BeatsWest or ', + ['"', '")'], + 'should suggest in phrase after grouping with term', + allCarrierValueSuggestions + ); + + testAroundClosing( + 'Carrier: ("BeatsWest" or ', + [undefined, ')'], + 'should suggest after grouping with phrase', + carrierWithNotSuggestions, + true + ); + + testAroundClosing( + 'Carrier: ("BeatsWest" or ', + ['"', '")'], + 'should suggest in phrase after grouping with phrase', + allCarrierValueSuggestions + ); +}); diff --git a/src/plugins/data/public/antlr/dql/code_completion.ts b/src/plugins/data/public/antlr/dql/code_completion.ts index 6a10a519abaf..025c2118fbc7 100644 --- a/src/plugins/data/public/antlr/dql/code_completion.ts +++ b/src/plugins/data/public/antlr/dql/code_completion.ts @@ -5,30 +5,33 @@ import { CharStream, CommonTokenStream, TokenStream } from 'antlr4ng'; import { CodeCompletionCore } from 'antlr4-c3'; -import { HttpSetup } from 'opensearch-dashboards/public'; import { monaco } from '@osd/monaco'; import { DQLLexer } from './.generated/DQLLexer'; -import { DQLParser, KeyValueExpressionContext } from './.generated/DQLParser'; +import { + DQLParser, + GroupContentContext, + GroupExpressionContext, + KeyValueExpressionContext, +} from './.generated/DQLParser'; import { getTokenPosition } from '../shared/cursor'; import { IndexPattern, IndexPatternField } from '../../index_patterns'; -import { QuerySuggestionGetFnArgs } from '../../autocomplete'; +import { QuerySuggestion, QuerySuggestionGetFnArgs } from '../../autocomplete'; import { DQLParserVisitor } from './.generated/DQLParserVisitor'; +import { IDataPluginServices } from '../..'; import { getQueryService } from '../../services'; const findCursorIndex = ( tokenStream: TokenStream, cursorColumn: number, - cursorLine: number, - whitespaceToken: number + cursorLine: number ): number | undefined => { - const actualCursorCol = cursorColumn - 1; - for (let i = 0; i < tokenStream.size; i++) { const token = tokenStream.get(i); - const { startLine, endColumn, endLine } = getTokenPosition(token, whitespaceToken); + const { startLine, endColumn, endLine } = getTokenPosition(token, DQLParser.WS); - if (endLine > cursorLine || (startLine === cursorLine && endColumn >= actualCursorCol)) { - if (tokenStream.get(i).type === whitespaceToken || tokenStream.get(i).type === DQLParser.EQ) { + const moveToNextToken = [DQLParser.WS, DQLParser.EQ, DQLParser.LPAREN]; + if (endLine > cursorLine || (startLine === cursorLine && endColumn >= cursorColumn)) { + if (moveToNextToken.includes(tokenStream.get(i).type)) { return i + 1; } return i; @@ -45,38 +48,26 @@ const findFieldSuggestions = (indexPattern: IndexPattern) => { return idxField.name; }); - const fieldSuggestions: Array<{ - text: string; - type: monaco.languages.CompletionItemKind; - }> = fieldNames.map((field: string) => { + const fieldSuggestions: QuerySuggestion[] = fieldNames.map((field: string) => { return { text: field, type: monaco.languages.CompletionItemKind.Field, insertText: `${field}: `, + start: -1, + end: -1, }; }); return fieldSuggestions; }; -const getFieldSuggestedValues = async ( - indexTitle: string, - fieldName: string, - currentValue: string, - http?: HttpSetup -) => { - if (!http) return []; - return await http.fetch(`/api/opensearch-dashboards/suggestions/values/${indexTitle}`, { - method: 'POST', - body: JSON.stringify({ query: currentValue, field: fieldName, boolFilter: [] }), - }); -}; - const findValueSuggestions = async ( index: IndexPattern, field: string, value: string, - http?: HttpSetup + services: IDataPluginServices, + boolFilter?: any, + signal?: AbortSignal ) => { // check to see if last field is within index and if it can suggest values, first check // if .keyword appended field exists because that has values @@ -90,45 +81,26 @@ const findValueSuggestions = async ( if (idxField.name === field) return idxField; }); - if (matchedField?.type === 'boolean') { - return ['true', 'false']; - } - - if (!matchedField || !matchedField.aggregatable || matchedField.type !== 'string') return; + if (!matchedField) return; - // ask api for suggestions - return await getFieldSuggestedValues(index.title, matchedField.name, value, http); + return await services?.data.autocomplete.getValueSuggestions({ + indexPattern: index, + field: matchedField, + query: value, + boolFilter, + signal, + }); }; -// visitor for parsing the current query -class QueryVisitor extends DQLParserVisitor<{ field: string; value: string }> { - public visitKeyValueExpression = (ctx: KeyValueExpressionContext) => { - let foundValue = ''; - const getTextWithoutQuotes = (text: string | undefined) => text?.replace(/^["']|["']$/g, ''); - - if (ctx.value()?.PHRASE()) { - const phraseText = getTextWithoutQuotes(ctx.value()?.PHRASE()?.getText()); - if (phraseText) foundValue = phraseText; - } else if (ctx.value()?.tokenSearch()) { - const valueText = ctx.value()?.getText(); - if (valueText) foundValue = valueText; - } else if (ctx.groupExpression()) { - const lastGroupContent = getTextWithoutQuotes( - ctx.groupExpression()?.groupContent().at(-1)?.getText() - ); - if (lastGroupContent) foundValue = lastGroupContent; - } - return { field: ctx.field().getText(), value: foundValue }; - }; -} - export const getSuggestions = async ({ query, indexPattern, position, selectionEnd, services, -}: QuerySuggestionGetFnArgs) => { + boolFilter, + signal, +}: QuerySuggestionGetFnArgs): Promise => { if ( !services || !services.appName || @@ -141,8 +113,6 @@ export const getSuggestions = async ({ return []; } try { - const http = services.http; - const inputStream = CharStream.fromString(query); const lexer = new DQLLexer(inputStream); const tokenStream = new CommonTokenStream(lexer); @@ -150,13 +120,11 @@ export const getSuggestions = async ({ parser.removeErrorListeners(); const tree = parser.query(); - const visitor = new QueryVisitor(); - // find token index - const cursorColumn = position?.column ?? selectionEnd; + const cursorColumn = position?.column !== undefined ? position.column - 1 : selectionEnd; const cursorLine = position?.lineNumber ?? 1; - const cursorIndex = findCursorIndex(tokenStream, cursorColumn, cursorLine, DQLParser.WS) ?? 0; + const cursorIndex = findCursorIndex(tokenStream, cursorColumn, cursorLine) ?? 0; const core = new CodeCompletionCore(parser); @@ -177,21 +145,123 @@ export const getSuggestions = async ({ // gets candidates at specified token index const candidates = core.collectCandidates(cursorIndex); - const completions = []; + // manually remove NOT from candidates when cursor is in a phrase + if (tokenStream.get(cursorIndex).type === DQLParser.PHRASE) { + candidates.tokens.delete(DQLParser.NOT); + } + + const completions: QuerySuggestion[] = []; // check to see if field rule is a candidate. if so, suggest field names if (candidates.rules.has(DQLParser.RULE_field)) { completions.push(...findFieldSuggestions(indexPattern)); } + interface FoundLastValue { + field: string | undefined; + value: string | undefined; + } + + // visitor for parsing the current query + class QueryVisitor extends DQLParserVisitor { + public defaultResult = () => { + return { field: undefined, value: undefined }; + }; + + public aggregateResult = (aggregate: FoundLastValue, nextResult: FoundLastValue) => { + if (nextResult.field) { + return nextResult; + } + return aggregate; + }; + + public visitKeyValueExpression = (ctx: KeyValueExpressionContext) => { + const startPos = ctx.start?.start ?? -1; + let endPos = ctx.stop?.stop ?? -1; + + // find the WS token after the last KV token, pushing endPos out if applicable + const { stop: lastKVToken } = ctx.getSourceInterval(); + if (tokenStream.get(lastKVToken + 1).type === DQLParser.WS) { + endPos = tokenStream.get(lastKVToken + 1).stop; + } + + // early return if the cursor is not within the bounds of this KV pair + if (!(startPos <= cursorColumn && endPos + 1 >= cursorColumn)) + return { field: undefined, value: undefined }; + + // keep as empty string to intentionally return so if no value is found in value() + let foundValue = ''; + const getTextWithoutQuotes = (text: string | undefined) => + text?.replace(/^["']|["']$/g, ''); + + if (ctx.value()?.PHRASE()) { + const phraseText = getTextWithoutQuotes(ctx.value()?.PHRASE()?.getText()); + if (phraseText) foundValue = phraseText; + } else if (ctx.value()?.tokenSearch()) { + const valueText = ctx.value()?.getText(); + if (valueText) foundValue = valueText; + } else if (ctx.groupExpression()) { + // continue calls down the tree for value group expressions + const groupRes = this.visitGroupExpression(ctx.groupExpression()!); + // only pull value off of groupRes, field should be undefined + const lastGroupContent = getTextWithoutQuotes(groupRes.value); + if (lastGroupContent) foundValue = lastGroupContent; + } + return { field: ctx.field().getText(), value: foundValue }; + }; + + public visitGroupExpression = (ctx: GroupExpressionContext) => { + let foundValue = ''; + + // within the multiple group contents, call visitor on each one + ctx.groupContent().forEach((child) => { + const ret = this.visitGroupContent(child); + if (ret.value) foundValue = ret.value; + }); + + return { field: undefined, value: foundValue }; + }; + + public visitGroupContent = (ctx: GroupContentContext) => { + const startPos = ctx.start?.start ?? -1; + const endPos = ctx.stop?.stop ?? -1; + + // NOTE: currently there is no support to look for tokens after whitespace, only + // returning if the cursor is directly touching a token + + if (!(startPos <= cursorColumn && endPos + 1 >= cursorColumn)) + return { field: undefined, value: undefined }; + + // trigger group expression to find content within + const foundValue = !!ctx.groupExpression() + ? this.visitGroupExpression(ctx.groupExpression()!).value + : ctx.getText(); + + return { field: undefined, value: foundValue }; + }; + } + + const visitor = new QueryVisitor(); // find suggested values for the last found field (only for kvexpression rule) const { field: lastField = '', value: lastValue = '' } = visitor.visit(tree) ?? {}; if (!!lastField && candidates.tokens.has(DQLParser.PHRASE)) { - const values = await findValueSuggestions(indexPattern, lastField, lastValue ?? '', http); + const values = await findValueSuggestions( + indexPattern, + lastField, + lastValue ?? '', + services, + boolFilter, + signal + ); if (!!values) { completions.push( ...values?.map((val: any) => { - return { text: val, type: monaco.languages.CompletionItemKind.Value }; + return { + text: val, + type: monaco.languages.CompletionItemKind.Value, + start: -1, + end: -1, + }; }) ); } @@ -205,10 +275,14 @@ export const getSuggestions = async ({ } const tokenSymbolName = parser.vocabulary.getSymbolicName(token)?.toLowerCase(); - completions.push({ - text: tokenSymbolName, - type: monaco.languages.CompletionItemKind.Keyword, - }); + if (tokenSymbolName) { + completions.push({ + text: tokenSymbolName, + type: monaco.languages.CompletionItemKind.Keyword, + start: -1, + end: -1, + }); + } }); return completions; diff --git a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.interp b/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.interp deleted file mode 100644 index 2a27c7a74895..000000000000 --- a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.interp +++ /dev/null @@ -1,56 +0,0 @@ -token literal names: -null -null -null -null -'>' -'<' -'>=' -'<=' -':' -'(' -')' -null -null -null - -token symbolic names: -null -OR -AND -NOT -GT -LT -GE -LE -EQ -LPAREN -RPAREN -PHRASE -ID -WS - -rule names: -OR -AND -NOT -GT -LT -GE -LE -EQ -LPAREN -RPAREN -PHRASE -ID -WS - -channel names: -DEFAULT_TOKEN_CHANNEL -HIDDEN - -mode names: -DEFAULT_MODE - -atn: -[4, 0, 13, 78, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 5, 10, 57, 8, 10, 10, 10, 12, 10, 60, 9, 10, 1, 10, 3, 10, 63, 8, 10, 1, 11, 1, 11, 5, 11, 67, 8, 11, 10, 11, 12, 11, 70, 9, 11, 1, 12, 4, 12, 73, 8, 12, 11, 12, 12, 12, 74, 1, 12, 1, 12, 0, 0, 13, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 1, 0, 10, 2, 0, 79, 79, 111, 111, 2, 0, 82, 82, 114, 114, 2, 0, 65, 65, 97, 97, 2, 0, 78, 78, 110, 110, 2, 0, 68, 68, 100, 100, 2, 0, 84, 84, 116, 116, 2, 0, 34, 34, 92, 92, 5, 0, 42, 42, 48, 57, 65, 90, 95, 95, 97, 122, 6, 0, 42, 42, 46, 46, 48, 57, 65, 90, 95, 95, 97, 122, 3, 0, 9, 10, 13, 13, 32, 32, 81, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 1, 27, 1, 0, 0, 0, 3, 30, 1, 0, 0, 0, 5, 34, 1, 0, 0, 0, 7, 38, 1, 0, 0, 0, 9, 40, 1, 0, 0, 0, 11, 42, 1, 0, 0, 0, 13, 45, 1, 0, 0, 0, 15, 48, 1, 0, 0, 0, 17, 50, 1, 0, 0, 0, 19, 52, 1, 0, 0, 0, 21, 54, 1, 0, 0, 0, 23, 64, 1, 0, 0, 0, 25, 72, 1, 0, 0, 0, 27, 28, 7, 0, 0, 0, 28, 29, 7, 1, 0, 0, 29, 2, 1, 0, 0, 0, 30, 31, 7, 2, 0, 0, 31, 32, 7, 3, 0, 0, 32, 33, 7, 4, 0, 0, 33, 4, 1, 0, 0, 0, 34, 35, 7, 3, 0, 0, 35, 36, 7, 0, 0, 0, 36, 37, 7, 5, 0, 0, 37, 6, 1, 0, 0, 0, 38, 39, 5, 62, 0, 0, 39, 8, 1, 0, 0, 0, 40, 41, 5, 60, 0, 0, 41, 10, 1, 0, 0, 0, 42, 43, 5, 62, 0, 0, 43, 44, 5, 61, 0, 0, 44, 12, 1, 0, 0, 0, 45, 46, 5, 60, 0, 0, 46, 47, 5, 61, 0, 0, 47, 14, 1, 0, 0, 0, 48, 49, 5, 58, 0, 0, 49, 16, 1, 0, 0, 0, 50, 51, 5, 40, 0, 0, 51, 18, 1, 0, 0, 0, 52, 53, 5, 41, 0, 0, 53, 20, 1, 0, 0, 0, 54, 58, 5, 34, 0, 0, 55, 57, 8, 6, 0, 0, 56, 55, 1, 0, 0, 0, 57, 60, 1, 0, 0, 0, 58, 56, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 62, 1, 0, 0, 0, 60, 58, 1, 0, 0, 0, 61, 63, 5, 34, 0, 0, 62, 61, 1, 0, 0, 0, 62, 63, 1, 0, 0, 0, 63, 22, 1, 0, 0, 0, 64, 68, 7, 7, 0, 0, 65, 67, 7, 8, 0, 0, 66, 65, 1, 0, 0, 0, 67, 70, 1, 0, 0, 0, 68, 66, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69, 24, 1, 0, 0, 0, 70, 68, 1, 0, 0, 0, 71, 73, 7, 9, 0, 0, 72, 71, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 72, 1, 0, 0, 0, 74, 75, 1, 0, 0, 0, 75, 76, 1, 0, 0, 0, 76, 77, 6, 12, 0, 0, 77, 26, 1, 0, 0, 0, 5, 0, 58, 62, 68, 74, 1, 0, 1, 0] \ No newline at end of file diff --git a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.java b/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.java deleted file mode 100644 index 82d84ce79e61..000000000000 --- a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.java +++ /dev/null @@ -1,166 +0,0 @@ -// Generated from /Users/paulstn/Documents/opensearch-2.15.0/OpenSearch-Dashboards/src/plugins/data/public/antlr/dql/grammar/DQLLexer.g4 by ANTLR 4.13.1 -import org.antlr.v4.runtime.Lexer; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.TokenStream; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.*; -import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.misc.*; - -@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) -public class DQLLexer extends Lexer { - static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); } - - protected static final DFA[] _decisionToDFA; - protected static final PredictionContextCache _sharedContextCache = - new PredictionContextCache(); - public static final int - OR=1, AND=2, NOT=3, GT=4, LT=5, GE=6, LE=7, EQ=8, LPAREN=9, RPAREN=10, - PHRASE=11, ID=12, WS=13; - public static String[] channelNames = { - "DEFAULT_TOKEN_CHANNEL", "HIDDEN" - }; - - public static String[] modeNames = { - "DEFAULT_MODE" - }; - - private static String[] makeRuleNames() { - return new String[] { - "OR", "AND", "NOT", "GT", "LT", "GE", "LE", "EQ", "LPAREN", "RPAREN", - "PHRASE", "ID", "WS" - }; - } - public static final String[] ruleNames = makeRuleNames(); - - private static String[] makeLiteralNames() { - return new String[] { - null, null, null, null, "'>'", "'<'", "'>='", "'<='", "':'", "'('", "')'" - }; - } - private static final String[] _LITERAL_NAMES = makeLiteralNames(); - private static String[] makeSymbolicNames() { - return new String[] { - null, "OR", "AND", "NOT", "GT", "LT", "GE", "LE", "EQ", "LPAREN", "RPAREN", - "PHRASE", "ID", "WS" - }; - } - private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); - public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); - - /** - * @deprecated Use {@link #VOCABULARY} instead. - */ - @Deprecated - public static final String[] tokenNames; - static { - tokenNames = new String[_SYMBOLIC_NAMES.length]; - for (int i = 0; i < tokenNames.length; i++) { - tokenNames[i] = VOCABULARY.getLiteralName(i); - if (tokenNames[i] == null) { - tokenNames[i] = VOCABULARY.getSymbolicName(i); - } - - if (tokenNames[i] == null) { - tokenNames[i] = ""; - } - } - } - - @Override - @Deprecated - public String[] getTokenNames() { - return tokenNames; - } - - @Override - - public Vocabulary getVocabulary() { - return VOCABULARY; - } - - - public DQLLexer(CharStream input) { - super(input); - _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); - } - - @Override - public String getGrammarFileName() { return "DQLLexer.g4"; } - - @Override - public String[] getRuleNames() { return ruleNames; } - - @Override - public String getSerializedATN() { return _serializedATN; } - - @Override - public String[] getChannelNames() { return channelNames; } - - @Override - public String[] getModeNames() { return modeNames; } - - @Override - public ATN getATN() { return _ATN; } - - public static final String _serializedATN = - "\u0004\u0000\rN\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+ - "\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+ - "\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+ - "\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+ - "\u0007\u000b\u0002\f\u0007\f\u0001\u0000\u0001\u0000\u0001\u0000\u0001"+ - "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0001\u0002\u0001"+ - "\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0001"+ - "\u0005\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+ - "\u0007\u0001\u0007\u0001\b\u0001\b\u0001\t\u0001\t\u0001\n\u0001\n\u0005"+ - "\n9\b\n\n\n\f\n<\t\n\u0001\n\u0003\n?\b\n\u0001\u000b\u0001\u000b\u0005"+ - "\u000bC\b\u000b\n\u000b\f\u000bF\t\u000b\u0001\f\u0004\fI\b\f\u000b\f"+ - "\f\fJ\u0001\f\u0001\f\u0000\u0000\r\u0001\u0001\u0003\u0002\u0005\u0003"+ - "\u0007\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013\n\u0015"+ - "\u000b\u0017\f\u0019\r\u0001\u0000\n\u0002\u0000OOoo\u0002\u0000RRrr\u0002"+ - "\u0000AAaa\u0002\u0000NNnn\u0002\u0000DDdd\u0002\u0000TTtt\u0002\u0000"+ - "\"\"\\\\\u0005\u0000**09AZ__az\u0006\u0000**..09AZ__az\u0003\u0000\t\n"+ - "\r\r Q\u0000\u0001\u0001\u0000\u0000\u0000\u0000\u0003\u0001\u0000\u0000"+ - "\u0000\u0000\u0005\u0001\u0000\u0000\u0000\u0000\u0007\u0001\u0000\u0000"+ - "\u0000\u0000\t\u0001\u0000\u0000\u0000\u0000\u000b\u0001\u0000\u0000\u0000"+ - "\u0000\r\u0001\u0000\u0000\u0000\u0000\u000f\u0001\u0000\u0000\u0000\u0000"+ - "\u0011\u0001\u0000\u0000\u0000\u0000\u0013\u0001\u0000\u0000\u0000\u0000"+ - "\u0015\u0001\u0000\u0000\u0000\u0000\u0017\u0001\u0000\u0000\u0000\u0000"+ - "\u0019\u0001\u0000\u0000\u0000\u0001\u001b\u0001\u0000\u0000\u0000\u0003"+ - "\u001e\u0001\u0000\u0000\u0000\u0005\"\u0001\u0000\u0000\u0000\u0007&"+ - "\u0001\u0000\u0000\u0000\t(\u0001\u0000\u0000\u0000\u000b*\u0001\u0000"+ - "\u0000\u0000\r-\u0001\u0000\u0000\u0000\u000f0\u0001\u0000\u0000\u0000"+ - "\u00112\u0001\u0000\u0000\u0000\u00134\u0001\u0000\u0000\u0000\u00156"+ - "\u0001\u0000\u0000\u0000\u0017@\u0001\u0000\u0000\u0000\u0019H\u0001\u0000"+ - "\u0000\u0000\u001b\u001c\u0007\u0000\u0000\u0000\u001c\u001d\u0007\u0001"+ - "\u0000\u0000\u001d\u0002\u0001\u0000\u0000\u0000\u001e\u001f\u0007\u0002"+ - "\u0000\u0000\u001f \u0007\u0003\u0000\u0000 !\u0007\u0004\u0000\u0000"+ - "!\u0004\u0001\u0000\u0000\u0000\"#\u0007\u0003\u0000\u0000#$\u0007\u0000"+ - "\u0000\u0000$%\u0007\u0005\u0000\u0000%\u0006\u0001\u0000\u0000\u0000"+ - "&\'\u0005>\u0000\u0000\'\b\u0001\u0000\u0000\u0000()\u0005<\u0000\u0000"+ - ")\n\u0001\u0000\u0000\u0000*+\u0005>\u0000\u0000+,\u0005=\u0000\u0000"+ - ",\f\u0001\u0000\u0000\u0000-.\u0005<\u0000\u0000./\u0005=\u0000\u0000"+ - "/\u000e\u0001\u0000\u0000\u000001\u0005:\u0000\u00001\u0010\u0001\u0000"+ - "\u0000\u000023\u0005(\u0000\u00003\u0012\u0001\u0000\u0000\u000045\u0005"+ - ")\u0000\u00005\u0014\u0001\u0000\u0000\u00006:\u0005\"\u0000\u000079\b"+ - "\u0006\u0000\u000087\u0001\u0000\u0000\u00009<\u0001\u0000\u0000\u0000"+ - ":8\u0001\u0000\u0000\u0000:;\u0001\u0000\u0000\u0000;>\u0001\u0000\u0000"+ - "\u0000<:\u0001\u0000\u0000\u0000=?\u0005\"\u0000\u0000>=\u0001\u0000\u0000"+ - "\u0000>?\u0001\u0000\u0000\u0000?\u0016\u0001\u0000\u0000\u0000@D\u0007"+ - "\u0007\u0000\u0000AC\u0007\b\u0000\u0000BA\u0001\u0000\u0000\u0000CF\u0001"+ - "\u0000\u0000\u0000DB\u0001\u0000\u0000\u0000DE\u0001\u0000\u0000\u0000"+ - "E\u0018\u0001\u0000\u0000\u0000FD\u0001\u0000\u0000\u0000GI\u0007\t\u0000"+ - "\u0000HG\u0001\u0000\u0000\u0000IJ\u0001\u0000\u0000\u0000JH\u0001\u0000"+ - "\u0000\u0000JK\u0001\u0000\u0000\u0000KL\u0001\u0000\u0000\u0000LM\u0006"+ - "\f\u0000\u0000M\u001a\u0001\u0000\u0000\u0000\u0005\u0000:>DJ\u0001\u0000"+ - "\u0001\u0000"; - public static final ATN _ATN = - new ATNDeserializer().deserialize(_serializedATN.toCharArray()); - static { - _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; - for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { - _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); - } - } -} \ No newline at end of file diff --git a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.tokens b/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.tokens deleted file mode 100644 index d9da629fcca1..000000000000 --- a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLLexer.tokens +++ /dev/null @@ -1,20 +0,0 @@ -OR=1 -AND=2 -NOT=3 -GT=4 -LT=5 -GE=6 -LE=7 -EQ=8 -LPAREN=9 -RPAREN=10 -PHRASE=11 -ID=12 -WS=13 -'>'=4 -'<'=5 -'>='=6 -'<='=7 -':'=8 -'('=9 -')'=10 diff --git a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.interp b/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.interp deleted file mode 100644 index 041e2baeae19..000000000000 --- a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.interp +++ /dev/null @@ -1,50 +0,0 @@ -token literal names: -null -null -null -null -'>' -'<' -'>=' -'<=' -':' -'(' -')' -null -null -null - -token symbolic names: -null -OR -AND -NOT -GT -LT -GE -LE -EQ -LPAREN -RPAREN -PHRASE -ID -WS - -rule names: -query -operatorExpression -booleanOperator -notExpression -primaryExpression -comparisonExpression -keyValueExpression -tokenSearch -groupExpression -groupContent -field -value -comparisonOperator - - -atn: -[4, 1, 13, 100, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 33, 8, 1, 10, 1, 12, 1, 36, 9, 1, 1, 2, 1, 2, 1, 3, 3, 3, 41, 8, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 52, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 62, 8, 6, 1, 7, 1, 7, 5, 7, 66, 8, 7, 10, 7, 12, 7, 69, 9, 7, 1, 8, 1, 8, 3, 8, 73, 8, 8, 1, 8, 1, 8, 1, 8, 3, 8, 78, 8, 8, 1, 8, 5, 8, 81, 8, 8, 10, 8, 12, 8, 84, 9, 8, 1, 8, 1, 8, 1, 9, 1, 9, 3, 9, 90, 8, 9, 1, 10, 1, 10, 1, 11, 1, 11, 3, 11, 96, 8, 11, 1, 12, 1, 12, 1, 12, 0, 0, 13, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 0, 2, 1, 0, 1, 2, 1, 0, 4, 7, 98, 0, 26, 1, 0, 0, 0, 2, 28, 1, 0, 0, 0, 4, 37, 1, 0, 0, 0, 6, 40, 1, 0, 0, 0, 8, 51, 1, 0, 0, 0, 10, 53, 1, 0, 0, 0, 12, 57, 1, 0, 0, 0, 14, 63, 1, 0, 0, 0, 16, 70, 1, 0, 0, 0, 18, 89, 1, 0, 0, 0, 20, 91, 1, 0, 0, 0, 22, 95, 1, 0, 0, 0, 24, 97, 1, 0, 0, 0, 26, 27, 3, 2, 1, 0, 27, 1, 1, 0, 0, 0, 28, 34, 3, 6, 3, 0, 29, 30, 3, 4, 2, 0, 30, 31, 3, 6, 3, 0, 31, 33, 1, 0, 0, 0, 32, 29, 1, 0, 0, 0, 33, 36, 1, 0, 0, 0, 34, 32, 1, 0, 0, 0, 34, 35, 1, 0, 0, 0, 35, 3, 1, 0, 0, 0, 36, 34, 1, 0, 0, 0, 37, 38, 7, 0, 0, 0, 38, 5, 1, 0, 0, 0, 39, 41, 5, 3, 0, 0, 40, 39, 1, 0, 0, 0, 40, 41, 1, 0, 0, 0, 41, 42, 1, 0, 0, 0, 42, 43, 3, 8, 4, 0, 43, 7, 1, 0, 0, 0, 44, 45, 5, 9, 0, 0, 45, 46, 3, 0, 0, 0, 46, 47, 5, 10, 0, 0, 47, 52, 1, 0, 0, 0, 48, 52, 3, 10, 5, 0, 49, 52, 3, 12, 6, 0, 50, 52, 3, 14, 7, 0, 51, 44, 1, 0, 0, 0, 51, 48, 1, 0, 0, 0, 51, 49, 1, 0, 0, 0, 51, 50, 1, 0, 0, 0, 52, 9, 1, 0, 0, 0, 53, 54, 3, 20, 10, 0, 54, 55, 3, 24, 12, 0, 55, 56, 3, 22, 11, 0, 56, 11, 1, 0, 0, 0, 57, 58, 3, 20, 10, 0, 58, 61, 5, 8, 0, 0, 59, 62, 3, 22, 11, 0, 60, 62, 3, 16, 8, 0, 61, 59, 1, 0, 0, 0, 61, 60, 1, 0, 0, 0, 62, 13, 1, 0, 0, 0, 63, 67, 5, 12, 0, 0, 64, 66, 5, 12, 0, 0, 65, 64, 1, 0, 0, 0, 66, 69, 1, 0, 0, 0, 67, 65, 1, 0, 0, 0, 67, 68, 1, 0, 0, 0, 68, 15, 1, 0, 0, 0, 69, 67, 1, 0, 0, 0, 70, 72, 5, 9, 0, 0, 71, 73, 5, 3, 0, 0, 72, 71, 1, 0, 0, 0, 72, 73, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 82, 3, 18, 9, 0, 75, 77, 7, 0, 0, 0, 76, 78, 5, 3, 0, 0, 77, 76, 1, 0, 0, 0, 77, 78, 1, 0, 0, 0, 78, 79, 1, 0, 0, 0, 79, 81, 3, 18, 9, 0, 80, 75, 1, 0, 0, 0, 81, 84, 1, 0, 0, 0, 82, 80, 1, 0, 0, 0, 82, 83, 1, 0, 0, 0, 83, 85, 1, 0, 0, 0, 84, 82, 1, 0, 0, 0, 85, 86, 5, 10, 0, 0, 86, 17, 1, 0, 0, 0, 87, 90, 3, 16, 8, 0, 88, 90, 3, 22, 11, 0, 89, 87, 1, 0, 0, 0, 89, 88, 1, 0, 0, 0, 90, 19, 1, 0, 0, 0, 91, 92, 5, 12, 0, 0, 92, 21, 1, 0, 0, 0, 93, 96, 5, 11, 0, 0, 94, 96, 3, 14, 7, 0, 95, 93, 1, 0, 0, 0, 95, 94, 1, 0, 0, 0, 96, 23, 1, 0, 0, 0, 97, 98, 7, 1, 0, 0, 98, 25, 1, 0, 0, 0, 10, 34, 40, 51, 61, 67, 72, 77, 82, 89, 95] \ No newline at end of file diff --git a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.java b/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.java deleted file mode 100644 index c55b54ae7a0f..000000000000 --- a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.java +++ /dev/null @@ -1,828 +0,0 @@ -// Generated from /Users/paulstn/Documents/opensearch-2.15.0/OpenSearch-Dashboards/src/plugins/data/public/antlr/dql/grammar/DQLParser.g4 by ANTLR 4.13.1 -import org.antlr.v4.runtime.atn.*; -import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.misc.*; -import org.antlr.v4.runtime.tree.*; -import java.util.List; -import java.util.Iterator; -import java.util.ArrayList; - -@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) -public class DQLParser extends Parser { - static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); } - - protected static final DFA[] _decisionToDFA; - protected static final PredictionContextCache _sharedContextCache = - new PredictionContextCache(); - public static final int - OR=1, AND=2, NOT=3, GT=4, LT=5, GE=6, LE=7, EQ=8, LPAREN=9, RPAREN=10, - PHRASE=11, ID=12, WS=13; - public static final int - RULE_query = 0, RULE_operatorExpression = 1, RULE_booleanOperator = 2, - RULE_notExpression = 3, RULE_primaryExpression = 4, RULE_comparisonExpression = 5, - RULE_keyValueExpression = 6, RULE_tokenSearch = 7, RULE_groupExpression = 8, - RULE_groupContent = 9, RULE_field = 10, RULE_value = 11, RULE_comparisonOperator = 12; - private static String[] makeRuleNames() { - return new String[] { - "query", "operatorExpression", "booleanOperator", "notExpression", "primaryExpression", - "comparisonExpression", "keyValueExpression", "tokenSearch", "groupExpression", - "groupContent", "field", "value", "comparisonOperator" - }; - } - public static final String[] ruleNames = makeRuleNames(); - - private static String[] makeLiteralNames() { - return new String[] { - null, null, null, null, "'>'", "'<'", "'>='", "'<='", "':'", "'('", "')'" - }; - } - private static final String[] _LITERAL_NAMES = makeLiteralNames(); - private static String[] makeSymbolicNames() { - return new String[] { - null, "OR", "AND", "NOT", "GT", "LT", "GE", "LE", "EQ", "LPAREN", "RPAREN", - "PHRASE", "ID", "WS" - }; - } - private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); - public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); - - /** - * @deprecated Use {@link #VOCABULARY} instead. - */ - @Deprecated - public static final String[] tokenNames; - static { - tokenNames = new String[_SYMBOLIC_NAMES.length]; - for (int i = 0; i < tokenNames.length; i++) { - tokenNames[i] = VOCABULARY.getLiteralName(i); - if (tokenNames[i] == null) { - tokenNames[i] = VOCABULARY.getSymbolicName(i); - } - - if (tokenNames[i] == null) { - tokenNames[i] = ""; - } - } - } - - @Override - @Deprecated - public String[] getTokenNames() { - return tokenNames; - } - - @Override - - public Vocabulary getVocabulary() { - return VOCABULARY; - } - - @Override - public String getGrammarFileName() { return "DQLParser.g4"; } - - @Override - public String[] getRuleNames() { return ruleNames; } - - @Override - public String getSerializedATN() { return _serializedATN; } - - @Override - public ATN getATN() { return _ATN; } - - public DQLParser(TokenStream input) { - super(input); - _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); - } - - @SuppressWarnings("CheckReturnValue") - public static class QueryContext extends ParserRuleContext { - public OperatorExpressionContext operatorExpression() { - return getRuleContext(OperatorExpressionContext.class,0); - } - public QueryContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_query; } - } - - public final QueryContext query() throws RecognitionException { - QueryContext _localctx = new QueryContext(_ctx, getState()); - enterRule(_localctx, 0, RULE_query); - try { - enterOuterAlt(_localctx, 1); - { - setState(26); - operatorExpression(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class OperatorExpressionContext extends ParserRuleContext { - public List notExpression() { - return getRuleContexts(NotExpressionContext.class); - } - public NotExpressionContext notExpression(int i) { - return getRuleContext(NotExpressionContext.class,i); - } - public List booleanOperator() { - return getRuleContexts(BooleanOperatorContext.class); - } - public BooleanOperatorContext booleanOperator(int i) { - return getRuleContext(BooleanOperatorContext.class,i); - } - public OperatorExpressionContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_operatorExpression; } - } - - public final OperatorExpressionContext operatorExpression() throws RecognitionException { - OperatorExpressionContext _localctx = new OperatorExpressionContext(_ctx, getState()); - enterRule(_localctx, 2, RULE_operatorExpression); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(28); - notExpression(); - setState(34); - _errHandler.sync(this); - _la = _input.LA(1); - while (_la==OR || _la==AND) { - { - { - setState(29); - booleanOperator(); - setState(30); - notExpression(); - } - } - setState(36); - _errHandler.sync(this); - _la = _input.LA(1); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class BooleanOperatorContext extends ParserRuleContext { - public TerminalNode OR() { return getToken(DQLParser.OR, 0); } - public TerminalNode AND() { return getToken(DQLParser.AND, 0); } - public BooleanOperatorContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_booleanOperator; } - } - - public final BooleanOperatorContext booleanOperator() throws RecognitionException { - BooleanOperatorContext _localctx = new BooleanOperatorContext(_ctx, getState()); - enterRule(_localctx, 4, RULE_booleanOperator); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(37); - _la = _input.LA(1); - if ( !(_la==OR || _la==AND) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class NotExpressionContext extends ParserRuleContext { - public PrimaryExpressionContext primaryExpression() { - return getRuleContext(PrimaryExpressionContext.class,0); - } - public TerminalNode NOT() { return getToken(DQLParser.NOT, 0); } - public NotExpressionContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_notExpression; } - } - - public final NotExpressionContext notExpression() throws RecognitionException { - NotExpressionContext _localctx = new NotExpressionContext(_ctx, getState()); - enterRule(_localctx, 6, RULE_notExpression); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(40); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==NOT) { - { - setState(39); - match(NOT); - } - } - - setState(42); - primaryExpression(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class PrimaryExpressionContext extends ParserRuleContext { - public TerminalNode LPAREN() { return getToken(DQLParser.LPAREN, 0); } - public QueryContext query() { - return getRuleContext(QueryContext.class,0); - } - public TerminalNode RPAREN() { return getToken(DQLParser.RPAREN, 0); } - public ComparisonExpressionContext comparisonExpression() { - return getRuleContext(ComparisonExpressionContext.class,0); - } - public KeyValueExpressionContext keyValueExpression() { - return getRuleContext(KeyValueExpressionContext.class,0); - } - public TokenSearchContext tokenSearch() { - return getRuleContext(TokenSearchContext.class,0); - } - public PrimaryExpressionContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_primaryExpression; } - } - - public final PrimaryExpressionContext primaryExpression() throws RecognitionException { - PrimaryExpressionContext _localctx = new PrimaryExpressionContext(_ctx, getState()); - enterRule(_localctx, 8, RULE_primaryExpression); - try { - setState(51); - _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) { - case 1: - enterOuterAlt(_localctx, 1); - { - setState(44); - match(LPAREN); - setState(45); - query(); - setState(46); - match(RPAREN); - } - break; - case 2: - enterOuterAlt(_localctx, 2); - { - setState(48); - comparisonExpression(); - } - break; - case 3: - enterOuterAlt(_localctx, 3); - { - setState(49); - keyValueExpression(); - } - break; - case 4: - enterOuterAlt(_localctx, 4); - { - setState(50); - tokenSearch(); - } - break; - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ComparisonExpressionContext extends ParserRuleContext { - public FieldContext field() { - return getRuleContext(FieldContext.class,0); - } - public ComparisonOperatorContext comparisonOperator() { - return getRuleContext(ComparisonOperatorContext.class,0); - } - public ValueContext value() { - return getRuleContext(ValueContext.class,0); - } - public ComparisonExpressionContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_comparisonExpression; } - } - - public final ComparisonExpressionContext comparisonExpression() throws RecognitionException { - ComparisonExpressionContext _localctx = new ComparisonExpressionContext(_ctx, getState()); - enterRule(_localctx, 10, RULE_comparisonExpression); - try { - enterOuterAlt(_localctx, 1); - { - setState(53); - field(); - setState(54); - comparisonOperator(); - setState(55); - value(); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class KeyValueExpressionContext extends ParserRuleContext { - public FieldContext field() { - return getRuleContext(FieldContext.class,0); - } - public TerminalNode EQ() { return getToken(DQLParser.EQ, 0); } - public ValueContext value() { - return getRuleContext(ValueContext.class,0); - } - public GroupExpressionContext groupExpression() { - return getRuleContext(GroupExpressionContext.class,0); - } - public KeyValueExpressionContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_keyValueExpression; } - } - - public final KeyValueExpressionContext keyValueExpression() throws RecognitionException { - KeyValueExpressionContext _localctx = new KeyValueExpressionContext(_ctx, getState()); - enterRule(_localctx, 12, RULE_keyValueExpression); - try { - enterOuterAlt(_localctx, 1); - { - setState(57); - field(); - setState(58); - match(EQ); - setState(61); - _errHandler.sync(this); - switch (_input.LA(1)) { - case PHRASE: - case ID: - { - setState(59); - value(); - } - break; - case LPAREN: - { - setState(60); - groupExpression(); - } - break; - default: - throw new NoViableAltException(this); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class TokenSearchContext extends ParserRuleContext { - public List ID() { return getTokens(DQLParser.ID); } - public TerminalNode ID(int i) { - return getToken(DQLParser.ID, i); - } - public TokenSearchContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_tokenSearch; } - } - - public final TokenSearchContext tokenSearch() throws RecognitionException { - TokenSearchContext _localctx = new TokenSearchContext(_ctx, getState()); - enterRule(_localctx, 14, RULE_tokenSearch); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(63); - match(ID); - setState(67); - _errHandler.sync(this); - _la = _input.LA(1); - while (_la==ID) { - { - { - setState(64); - match(ID); - } - } - setState(69); - _errHandler.sync(this); - _la = _input.LA(1); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class GroupExpressionContext extends ParserRuleContext { - public TerminalNode LPAREN() { return getToken(DQLParser.LPAREN, 0); } - public List groupContent() { - return getRuleContexts(GroupContentContext.class); - } - public GroupContentContext groupContent(int i) { - return getRuleContext(GroupContentContext.class,i); - } - public TerminalNode RPAREN() { return getToken(DQLParser.RPAREN, 0); } - public List NOT() { return getTokens(DQLParser.NOT); } - public TerminalNode NOT(int i) { - return getToken(DQLParser.NOT, i); - } - public List OR() { return getTokens(DQLParser.OR); } - public TerminalNode OR(int i) { - return getToken(DQLParser.OR, i); - } - public List AND() { return getTokens(DQLParser.AND); } - public TerminalNode AND(int i) { - return getToken(DQLParser.AND, i); - } - public GroupExpressionContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_groupExpression; } - } - - public final GroupExpressionContext groupExpression() throws RecognitionException { - GroupExpressionContext _localctx = new GroupExpressionContext(_ctx, getState()); - enterRule(_localctx, 16, RULE_groupExpression); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(70); - match(LPAREN); - setState(72); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==NOT) { - { - setState(71); - match(NOT); - } - } - - setState(74); - groupContent(); - setState(82); - _errHandler.sync(this); - _la = _input.LA(1); - while (_la==OR || _la==AND) { - { - { - setState(75); - _la = _input.LA(1); - if ( !(_la==OR || _la==AND) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - setState(77); - _errHandler.sync(this); - _la = _input.LA(1); - if (_la==NOT) { - { - setState(76); - match(NOT); - } - } - - setState(79); - groupContent(); - } - } - setState(84); - _errHandler.sync(this); - _la = _input.LA(1); - } - setState(85); - match(RPAREN); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class GroupContentContext extends ParserRuleContext { - public GroupExpressionContext groupExpression() { - return getRuleContext(GroupExpressionContext.class,0); - } - public ValueContext value() { - return getRuleContext(ValueContext.class,0); - } - public GroupContentContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_groupContent; } - } - - public final GroupContentContext groupContent() throws RecognitionException { - GroupContentContext _localctx = new GroupContentContext(_ctx, getState()); - enterRule(_localctx, 18, RULE_groupContent); - try { - setState(89); - _errHandler.sync(this); - switch (_input.LA(1)) { - case LPAREN: - enterOuterAlt(_localctx, 1); - { - setState(87); - groupExpression(); - } - break; - case PHRASE: - case ID: - enterOuterAlt(_localctx, 2); - { - setState(88); - value(); - } - break; - default: - throw new NoViableAltException(this); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class FieldContext extends ParserRuleContext { - public TerminalNode ID() { return getToken(DQLParser.ID, 0); } - public FieldContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_field; } - } - - public final FieldContext field() throws RecognitionException { - FieldContext _localctx = new FieldContext(_ctx, getState()); - enterRule(_localctx, 20, RULE_field); - try { - enterOuterAlt(_localctx, 1); - { - setState(91); - match(ID); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ValueContext extends ParserRuleContext { - public TerminalNode PHRASE() { return getToken(DQLParser.PHRASE, 0); } - public TokenSearchContext tokenSearch() { - return getRuleContext(TokenSearchContext.class,0); - } - public ValueContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_value; } - } - - public final ValueContext value() throws RecognitionException { - ValueContext _localctx = new ValueContext(_ctx, getState()); - enterRule(_localctx, 22, RULE_value); - try { - setState(95); - _errHandler.sync(this); - switch (_input.LA(1)) { - case PHRASE: - enterOuterAlt(_localctx, 1); - { - setState(93); - match(PHRASE); - } - break; - case ID: - enterOuterAlt(_localctx, 2); - { - setState(94); - tokenSearch(); - } - break; - default: - throw new NoViableAltException(this); - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - @SuppressWarnings("CheckReturnValue") - public static class ComparisonOperatorContext extends ParserRuleContext { - public TerminalNode GT() { return getToken(DQLParser.GT, 0); } - public TerminalNode LT() { return getToken(DQLParser.LT, 0); } - public TerminalNode GE() { return getToken(DQLParser.GE, 0); } - public TerminalNode LE() { return getToken(DQLParser.LE, 0); } - public ComparisonOperatorContext(ParserRuleContext parent, int invokingState) { - super(parent, invokingState); - } - @Override public int getRuleIndex() { return RULE_comparisonOperator; } - } - - public final ComparisonOperatorContext comparisonOperator() throws RecognitionException { - ComparisonOperatorContext _localctx = new ComparisonOperatorContext(_ctx, getState()); - enterRule(_localctx, 24, RULE_comparisonOperator); - int _la; - try { - enterOuterAlt(_localctx, 1); - { - setState(97); - _la = _input.LA(1); - if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 240L) != 0)) ) { - _errHandler.recoverInline(this); - } - else { - if ( _input.LA(1)==Token.EOF ) matchedEOF = true; - _errHandler.reportMatch(this); - consume(); - } - } - } - catch (RecognitionException re) { - _localctx.exception = re; - _errHandler.reportError(this, re); - _errHandler.recover(this, re); - } - finally { - exitRule(); - } - return _localctx; - } - - public static final String _serializedATN = - "\u0004\u0001\rd\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ - "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ - "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ - "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ - "\f\u0007\f\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0001\u0001\u0005\u0001!\b\u0001\n\u0001\f\u0001$\t\u0001\u0001\u0002"+ - "\u0001\u0002\u0001\u0003\u0003\u0003)\b\u0003\u0001\u0003\u0001\u0003"+ - "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004"+ - "\u0001\u0004\u0003\u00044\b\u0004\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006"+ - ">\b\u0006\u0001\u0007\u0001\u0007\u0005\u0007B\b\u0007\n\u0007\f\u0007"+ - "E\t\u0007\u0001\b\u0001\b\u0003\bI\b\b\u0001\b\u0001\b\u0001\b\u0003\b"+ - "N\b\b\u0001\b\u0005\bQ\b\b\n\b\f\bT\t\b\u0001\b\u0001\b\u0001\t\u0001"+ - "\t\u0003\tZ\b\t\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0003\u000b`\b"+ - "\u000b\u0001\f\u0001\f\u0001\f\u0000\u0000\r\u0000\u0002\u0004\u0006\b"+ - "\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u0000\u0002\u0001\u0000\u0001"+ - "\u0002\u0001\u0000\u0004\u0007b\u0000\u001a\u0001\u0000\u0000\u0000\u0002"+ - "\u001c\u0001\u0000\u0000\u0000\u0004%\u0001\u0000\u0000\u0000\u0006(\u0001"+ - "\u0000\u0000\u0000\b3\u0001\u0000\u0000\u0000\n5\u0001\u0000\u0000\u0000"+ - "\f9\u0001\u0000\u0000\u0000\u000e?\u0001\u0000\u0000\u0000\u0010F\u0001"+ - "\u0000\u0000\u0000\u0012Y\u0001\u0000\u0000\u0000\u0014[\u0001\u0000\u0000"+ - "\u0000\u0016_\u0001\u0000\u0000\u0000\u0018a\u0001\u0000\u0000\u0000\u001a"+ - "\u001b\u0003\u0002\u0001\u0000\u001b\u0001\u0001\u0000\u0000\u0000\u001c"+ - "\"\u0003\u0006\u0003\u0000\u001d\u001e\u0003\u0004\u0002\u0000\u001e\u001f"+ - "\u0003\u0006\u0003\u0000\u001f!\u0001\u0000\u0000\u0000 \u001d\u0001\u0000"+ - "\u0000\u0000!$\u0001\u0000\u0000\u0000\" \u0001\u0000\u0000\u0000\"#\u0001"+ - "\u0000\u0000\u0000#\u0003\u0001\u0000\u0000\u0000$\"\u0001\u0000\u0000"+ - "\u0000%&\u0007\u0000\u0000\u0000&\u0005\u0001\u0000\u0000\u0000\')\u0005"+ - "\u0003\u0000\u0000(\'\u0001\u0000\u0000\u0000()\u0001\u0000\u0000\u0000"+ - ")*\u0001\u0000\u0000\u0000*+\u0003\b\u0004\u0000+\u0007\u0001\u0000\u0000"+ - "\u0000,-\u0005\t\u0000\u0000-.\u0003\u0000\u0000\u0000./\u0005\n\u0000"+ - "\u0000/4\u0001\u0000\u0000\u000004\u0003\n\u0005\u000014\u0003\f\u0006"+ - "\u000024\u0003\u000e\u0007\u00003,\u0001\u0000\u0000\u000030\u0001\u0000"+ - "\u0000\u000031\u0001\u0000\u0000\u000032\u0001\u0000\u0000\u00004\t\u0001"+ - "\u0000\u0000\u000056\u0003\u0014\n\u000067\u0003\u0018\f\u000078\u0003"+ - "\u0016\u000b\u00008\u000b\u0001\u0000\u0000\u00009:\u0003\u0014\n\u0000"+ - ":=\u0005\b\u0000\u0000;>\u0003\u0016\u000b\u0000<>\u0003\u0010\b\u0000"+ - "=;\u0001\u0000\u0000\u0000=<\u0001\u0000\u0000\u0000>\r\u0001\u0000\u0000"+ - "\u0000?C\u0005\f\u0000\u0000@B\u0005\f\u0000\u0000A@\u0001\u0000\u0000"+ - "\u0000BE\u0001\u0000\u0000\u0000CA\u0001\u0000\u0000\u0000CD\u0001\u0000"+ - "\u0000\u0000D\u000f\u0001\u0000\u0000\u0000EC\u0001\u0000\u0000\u0000"+ - "FH\u0005\t\u0000\u0000GI\u0005\u0003\u0000\u0000HG\u0001\u0000\u0000\u0000"+ - "HI\u0001\u0000\u0000\u0000IJ\u0001\u0000\u0000\u0000JR\u0003\u0012\t\u0000"+ - "KM\u0007\u0000\u0000\u0000LN\u0005\u0003\u0000\u0000ML\u0001\u0000\u0000"+ - "\u0000MN\u0001\u0000\u0000\u0000NO\u0001\u0000\u0000\u0000OQ\u0003\u0012"+ - "\t\u0000PK\u0001\u0000\u0000\u0000QT\u0001\u0000\u0000\u0000RP\u0001\u0000"+ - "\u0000\u0000RS\u0001\u0000\u0000\u0000SU\u0001\u0000\u0000\u0000TR\u0001"+ - "\u0000\u0000\u0000UV\u0005\n\u0000\u0000V\u0011\u0001\u0000\u0000\u0000"+ - "WZ\u0003\u0010\b\u0000XZ\u0003\u0016\u000b\u0000YW\u0001\u0000\u0000\u0000"+ - "YX\u0001\u0000\u0000\u0000Z\u0013\u0001\u0000\u0000\u0000[\\\u0005\f\u0000"+ - "\u0000\\\u0015\u0001\u0000\u0000\u0000]`\u0005\u000b\u0000\u0000^`\u0003"+ - "\u000e\u0007\u0000_]\u0001\u0000\u0000\u0000_^\u0001\u0000\u0000\u0000"+ - "`\u0017\u0001\u0000\u0000\u0000ab\u0007\u0001\u0000\u0000b\u0019\u0001"+ - "\u0000\u0000\u0000\n\"(3=CHMRY_"; - public static final ATN _ATN = - new ATNDeserializer().deserialize(_serializedATN.toCharArray()); - static { - _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; - for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { - _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); - } - } -} \ No newline at end of file diff --git a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.tokens b/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.tokens deleted file mode 100644 index d9da629fcca1..000000000000 --- a/src/plugins/data/public/antlr/dql/grammar/.antlr/DQLParser.tokens +++ /dev/null @@ -1,20 +0,0 @@ -OR=1 -AND=2 -NOT=3 -GT=4 -LT=5 -GE=6 -LE=7 -EQ=8 -LPAREN=9 -RPAREN=10 -PHRASE=11 -ID=12 -WS=13 -'>'=4 -'<'=5 -'>='=6 -'<='=7 -':'=8 -'('=9 -')'=10 diff --git a/src/plugins/data/public/antlr/shared/constants.ts b/src/plugins/data/public/antlr/shared/constants.ts deleted file mode 100644 index d0dbc0f70eac..000000000000 --- a/src/plugins/data/public/antlr/shared/constants.ts +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { IndexPattern } from '../..'; - -export const testingIndex = ({ - title: 'opensearch_dashboards_sample_data_flights', - fields: [ - { - count: 0, - name: 'Carrier', - displayName: 'Carrier', - type: 'string', - esTypes: ['keyword'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: undefined, - }, - { - count: 2, - name: 'DestCityName', - displayName: 'DestCityName', - type: 'string', - esTypes: ['keyword'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: undefined, - }, - { - count: 0, - name: 'DestCountry', - displayName: 'DestCountry', - type: 'string', - esTypes: ['keyword'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: undefined, - }, - { - count: 0, - name: 'DestWeather', - displayName: 'DestWeather', - type: 'string', - esTypes: ['keyword'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: undefined, - }, - { - count: 0, - name: 'DistanceMiles', - displayName: 'DistanceMiles', - type: 'number', - esTypes: ['float'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: undefined, - }, - { - count: 0, - name: 'FlightDelay', - displayName: 'FlightDelay', - type: 'boolean', - esTypes: ['boolean'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: undefined, - }, - { - count: 0, - name: 'FlightNum', - displayName: 'FlightNum', - type: 'string', - esTypes: ['keyword'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: undefined, - }, - { - count: 0, - name: 'OriginWeather', - displayName: 'OriginWeather', - type: 'string', - esTypes: ['keyword'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: true, - subType: undefined, - }, - { - count: 0, - name: '_id', - displayName: '_id', - type: 'string', - esTypes: ['_id'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: false, - subType: undefined, - }, - { - count: 0, - name: '_index', - displayName: '_index', - type: 'string', - esTypes: ['_index'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: false, - subType: undefined, - }, - { - count: 0, - name: '_score', - displayName: '_score', - type: 'number', - scripted: false, - searchable: false, - aggregatable: false, - readFromDocValues: false, - subType: undefined, - }, - { - count: 0, - name: '_source', - displayName: '_source', - type: '_source', - esTypes: ['_source'], - scripted: false, - searchable: false, - aggregatable: false, - readFromDocValues: false, - subType: undefined, - }, - { - count: 0, - name: '_type', - displayName: '_type', - type: 'string', - esTypes: ['_type'], - scripted: false, - searchable: true, - aggregatable: true, - readFromDocValues: false, - subType: undefined, - }, - ], -} as unknown) as IndexPattern; - -export const booleanOperatorSuggestions = [ - { text: 'or', type: 17 }, - { text: 'and', type: 17 }, -]; - -export const notOperatorSuggestion = { text: 'not', type: 17 }; - -export const fieldNameSuggestions: Array<{ text: string; type: number; insertText?: string }> = [ - { text: 'Carrier', type: 3, insertText: 'Carrier: ' }, - { text: 'DestCityName', type: 3, insertText: 'DestCityName: ' }, - { text: 'DestCountry', type: 3, insertText: 'DestCountry: ' }, - { text: 'DestWeather', type: 3, insertText: 'DestWeather: ' }, - { text: 'DistanceMiles', type: 3, insertText: 'DistanceMiles: ' }, - { text: 'FlightDelay', type: 3, insertText: 'FlightDelay: ' }, - { text: 'FlightNum', type: 3, insertText: 'FlightNum: ' }, - { text: 'OriginWeather', type: 3, insertText: 'OriginWeather: ' }, - { text: '_id', type: 3, insertText: '_id: ' }, - { text: '_index', type: 3, insertText: '_index: ' }, - { text: '_score', type: 3, insertText: '_score: ' }, - { text: '_source', type: 3, insertText: '_source: ' }, - { text: '_type', type: 3, insertText: '_type: ' }, -]; - -export const fieldNameWithNotSuggestions = fieldNameSuggestions.concat(notOperatorSuggestion); diff --git a/src/plugins/data/public/autocomplete/autocomplete_service.ts b/src/plugins/data/public/autocomplete/autocomplete_service.ts index 4eec6f48079d..44e414581575 100644 --- a/src/plugins/data/public/autocomplete/autocomplete_service.ts +++ b/src/plugins/data/public/autocomplete/autocomplete_service.ts @@ -47,8 +47,6 @@ export class AutocompleteService { this.autocompleteConfig = autocomplete; } - private core: CoreSetup | undefined; - private readonly querySuggestionProviders: Map = new Map(); private getValueSuggestions?: ValueSuggestionsGetFn; @@ -63,7 +61,7 @@ export class AutocompleteService { const provider = this.querySuggestionProviders.get(language); if (provider) { - return provider({ core: this.core, ...args }); + return provider(args); } }; @@ -75,8 +73,6 @@ export class AutocompleteService { ? setupValueSuggestionProvider(core) : getEmptyValueSuggestions; - this.core = core; - return { addQuerySuggestionProvider: this.addQuerySuggestionProvider, diff --git a/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts index 9b41fe8bb67f..636a4a1993b6 100644 --- a/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts @@ -29,7 +29,6 @@ */ import { monaco } from '@osd/monaco'; -import { CoreSetup } from 'opensearch-dashboards/public'; import { IFieldType, IndexPattern } from '../../../common/index_patterns'; import { IDataPluginServices } from '../../types'; @@ -56,7 +55,6 @@ export interface QuerySuggestionGetFnArgs { boolFilter?: any; position?: monaco.Position; services?: IDataPluginServices; - core?: CoreSetup; } /** @public **/ @@ -66,7 +64,7 @@ export interface QuerySuggestionBasic { end: number; start: number; text: string; - insertText: string; + insertText?: string; cursorIndex?: number; } diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index 62eca6bac579..b94c38d0f15e 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -47,7 +47,7 @@ import { import { FormattedMessage } from '@osd/i18n/react'; import { debounce, compact, isEqual, isFunction } from 'lodash'; import { Toast } from 'src/core/public'; -import { IDataPluginServices, IIndexPattern, Query } from '../..'; +import { IDataPluginServices, IIndexPattern, IndexPattern, Query } from '../..'; import { QuerySuggestion, QuerySuggestionTypes } from '../../autocomplete'; import { @@ -184,7 +184,7 @@ export default class QueryStringInputUI extends Component { const suggestions = (await this.services.data.autocomplete.getQuerySuggestions({ language, - indexPatterns, + indexPattern: indexPatterns[0] as IndexPattern, query: queryString, selectionStart, selectionEnd, diff --git a/src/plugins/opensearch_dashboards_react/public/code_editor/code_editor.tsx b/src/plugins/opensearch_dashboards_react/public/code_editor/code_editor.tsx index bc3a330c6081..8996297775c9 100644 --- a/src/plugins/opensearch_dashboards_react/public/code_editor/code_editor.tsx +++ b/src/plugins/opensearch_dashboards_react/public/code_editor/code_editor.tsx @@ -38,14 +38,6 @@ import { LIGHT_THEME, DARK_THEME } from './editor_theme'; import './editor.scss'; -export interface LanguageSpecifiedConfiguration extends monaco.languages.LanguageConfiguration { - /** - * The language ID, meant to restrict the specified configuration for only this language. When - * not provided, will apply the language configuration for every language. - */ - language?: string; -} - export interface Props { /** Width of editor. Defaults to 100%. */ width?: string | number; @@ -65,37 +57,37 @@ export interface Props { /** * Options for the Monaco Code Editor * Documentation of options can be found here: - * https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.ieditorconstructionoptions.html + * https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IEditorConstructionOptions.html */ options?: monaco.editor.IEditorConstructionOptions; /** * Suggestion provider for autocompletion * Documentation for the provider can be found here: - * https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.completionitemprovider.html + * https://microsoft.github.io/monaco-editor/docs.html#interfaces/languages.CompletionItemProvider.html */ suggestionProvider?: monaco.languages.CompletionItemProvider; /** * Signature provider for function parameter info * Documentation for the provider can be found here: - * https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.signaturehelpprovider.html + * https://microsoft.github.io/monaco-editor/docs.html#interfaces/languages.SignatureHelpProvider.html */ signatureProvider?: monaco.languages.SignatureHelpProvider; /** * Hover provider for hover documentation * Documentation for the provider can be found here: - * https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.hoverprovider.html + * https://microsoft.github.io/monaco-editor/docs.html#interfaces/languages.HoverProvider.html */ hoverProvider?: monaco.languages.HoverProvider; /** * Language config provider for bracket * Documentation for the provider can be found here: - * https://microsoft.github.io/monaco-editor/api/interfaces/monaco.languages.languageconfiguration.html + * https://microsoft.github.io/monaco-editor/docs.html#interfaces/languages.LanguageConfiguration.html */ - languageConfiguration?: LanguageSpecifiedConfiguration; + languageConfiguration?: monaco.languages.LanguageConfiguration; /** * Function called before the editor is mounted in the view @@ -168,17 +160,7 @@ export class CodeEditor extends React.Component { } if (this.props.languageConfiguration) { - // if the language isn't specified or the language configuration specified language - // matches, use the configuration - if ( - !this.props.languageConfiguration.language || - this.props.languageConfiguration.language === languageId - ) { - monaco.languages.setLanguageConfiguration( - this.props.languageId, - this.props.languageConfiguration - ); - } + monaco.languages.setLanguageConfiguration(languageId, this.props.languageConfiguration); } }); From 9b17f409e46f6fdf8ecb17c56eed7d6064eaf17e Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:29:12 -0700 Subject: [PATCH 257/276] [discover] update query assist icon (#7898) (#7899) (cherry picked from commit 7a8e4270a9cca875bd1546fa1a6a82214b0f90d9) Signed-off-by: Joshua Li Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../public/assets/query_assist_mark.svg | 38 ++++++++++--------- .../query_assist/utils/create_extension.tsx | 7 +++- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/plugins/query_enhancements/public/assets/query_assist_mark.svg b/src/plugins/query_enhancements/public/assets/query_assist_mark.svg index b744e8c35e8f..01699001144d 100644 --- a/src/plugins/query_enhancements/public/assets/query_assist_mark.svg +++ b/src/plugins/query_enhancements/public/assets/query_assist_mark.svg @@ -1,18 +1,22 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx index ac56f35a7281..3b0b12760749 100644 --- a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx +++ b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { i18n } from '@osd/i18n'; import { HttpSetup } from 'opensearch-dashboards/public'; import React, { useEffect, useState } from 'react'; import { distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators'; @@ -14,8 +15,8 @@ import { } from '../../../../data/public'; import { API } from '../../../common'; import { ConfigSchema } from '../../../common/config'; -import { QueryAssistBanner, QueryAssistBar } from '../components'; import assistantMark from '../../assets/query_assist_mark.svg'; +import { QueryAssistBanner, QueryAssistBar } from '../components'; /** * @returns list of query assist supported languages for the given data source. @@ -84,7 +85,9 @@ export const createQueryAssistExtension = ( return { type: DATA_STRUCTURE_META_TYPES.FEATURE, icon: { type: assistantMark }, - tooltip: 'Query assist is available', + tooltip: i18n.translate('queryAssist.meta.icon.tooltip', { + defaultMessage: 'Query assist is available', + }), }; } }, From 72e1f92369cc2100405a35d7b7069e1d60cbe110 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:34:22 -0700 Subject: [PATCH 258/276] add tests for query assist extension and data structures utils (#7894) (#7897) (cherry picked from commit f9965cd29afec8996a0c7b7f5e6001ab41de924e) Signed-off-by: Joshua Li Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../dataset_service/lib/utils.test.ts | 82 +++++++++++++++++++ .../utils/create_extension.test.tsx | 59 +++++++++++-- .../query_assist/utils/create_extension.tsx | 54 ++++++------ 3 files changed, 166 insertions(+), 29 deletions(-) create mode 100644 src/plugins/data/public/query/query_string/dataset_service/lib/utils.test.ts diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/utils.test.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/utils.test.ts new file mode 100644 index 000000000000..d9231e1015da --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/utils.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { LanguageServiceContract } from '../..'; +import { IQueryStart } from '../../..'; +import { DataStructure, DATA_STRUCTURE_META_TYPES } from '../../../../../common'; +import { dataPluginMock } from '../../../../mocks'; +import { setQueryService } from '../../../../services'; +import { injectMetaToDataStructures } from './utils'; + +const mockDataStructures: DataStructure[] = [ + { + id: 'fe25e2a0-6566-11ef-bb0e-0b6b1035facb', + title: 'mock-index-pattern-title', + type: 'INDEX_PATTERN', + parent: { + id: '8f26d980-63f5-11ef-b231-09f3ad4fb0e0', + title: 'mock-data-source-title', + type: 'OpenSearch', + }, + meta: { type: DATA_STRUCTURE_META_TYPES.CUSTOM }, + }, +]; + +const dataMock = dataPluginMock.createSetupContract(); +const languageServiceMock = dataMock.query.queryString.getLanguageService() as jest.Mocked< + LanguageServiceContract +>; +setQueryService({ queryString: dataMock.query.queryString } as IQueryStart); + +languageServiceMock.getQueryEditorExtensionMap.mockReturnValue({ + 'mock-extension-1': { + id: 'mock-extension-1', + order: 1, + isEnabled$: jest.fn(), + getDataStructureMeta: (dataSourceId) => + Promise.resolve({ + type: DATA_STRUCTURE_META_TYPES.FEATURE, + icon: { type: 'icon1' }, + }), + }, + 'mock-extension-2': { + id: 'mock-extension-2', + order: 2, + isEnabled$: jest.fn(), + getDataStructureMeta: (dataSourceId) => + Promise.resolve({ + type: DATA_STRUCTURE_META_TYPES.FEATURE, + icon: { type: 'icon2' }, + tooltip: 'mock-extension-2', + }), + }, +}); + +describe('Utils injectMetaToDataStructures', () => { + it('should inject meta', async () => { + const dataStructures = await injectMetaToDataStructures(mockDataStructures); + expect(dataStructures[0].meta).toMatchInlineSnapshot(` + Object { + "icon": Object { + "type": "icon1", + }, + "tooltip": "mock-extension-2", + "type": "CUSTOM", + } + `); + }); + + it('does not change meta if not available', async () => { + languageServiceMock.getQueryEditorExtensionMap.mockReturnValue({ + 'mock-extension-3': { + id: 'mock-extension-3', + order: 3, + isEnabled$: jest.fn(), + }, + }); + const dataStructures = await injectMetaToDataStructures(mockDataStructures); + expect(dataStructures[0].meta).toBe(mockDataStructures[0].meta); + }); +}); diff --git a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.test.tsx b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.test.tsx index 955fd8cd1569..6d915d96ff09 100644 --- a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.test.tsx +++ b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.test.tsx @@ -6,11 +6,12 @@ import { firstValueFrom } from '@osd/std'; import { act, render, screen } from '@testing-library/react'; import React from 'react'; +import { of } from 'rxjs'; import { coreMock } from '../../../../../core/public/mocks'; -import { QueryEditorExtensionDependencies } from '../../../../data/public'; +import { QueryEditorExtensionDependencies, QueryStringContract } from '../../../../data/public'; import { dataPluginMock } from '../../../../data/public/mocks'; import { ConfigSchema } from '../../../common/config'; -import { createQueryAssistExtension } from './create_extension'; +import { clearCache, createQueryAssistExtension } from './create_extension'; const coreSetupMock = coreMock.createSetup({ pluginStartDeps: { @@ -21,14 +22,32 @@ const coreSetupMock = coreMock.createSetup({ }); const httpMock = coreSetupMock.http; const dataMock = dataPluginMock.createSetupContract(); +const queryStringMock = dataMock.query.queryString as jest.Mocked; + +const mockQueryWithIndexPattern = { + query: '', + language: 'kuery', + dataset: { + id: 'mock-index-pattern-id', + title: 'mock-index', + type: 'INDEX_PATTERN', + dataSource: { + id: 'mock-data-source-id', + title: 'test-mds', + type: 'OpenSearch', + }, + }, +}; + +queryStringMock.getQuery.mockReturnValue(mockQueryWithIndexPattern); +queryStringMock.getUpdates$.mockReturnValue(of(mockQueryWithIndexPattern)); jest.mock('../components', () => ({ QueryAssistBar: jest.fn(() =>
QueryAssistBar
), QueryAssistBanner: jest.fn(() =>
QueryAssistBanner
), })); -// TODO: https://github.com/opensearch-project/OpenSearch-Dashboards/issues/7860 -describe.skip('CreateExtension', () => { +describe('CreateExtension', () => { const dependencies: QueryEditorExtensionDependencies = { language: 'PPL', onSelectLanguage: jest.fn(), @@ -37,6 +56,7 @@ describe.skip('CreateExtension', () => { }; afterEach(() => { jest.clearAllMocks(); + clearCache(); }); const config: ConfigSchema['queryAssist'] = { @@ -53,7 +73,7 @@ describe.skip('CreateExtension', () => { }); }); - it('should be disabled for unsupported language', async () => { + it('should be disabled when there is an error', async () => { httpMock.get.mockRejectedValueOnce(new Error('network failure')); const extension = createQueryAssistExtension(httpMock, dataMock, config); const isEnabled = await firstValueFrom(extension.isEnabled$(dependencies)); @@ -63,6 +83,35 @@ describe.skip('CreateExtension', () => { }); }); + it('creates data structure meta', async () => { + httpMock.get.mockResolvedValueOnce({ configuredLanguages: ['PPL'] }); + const extension = createQueryAssistExtension(httpMock, dataMock, config); + const meta = await extension.getDataStructureMeta?.('mock-data-source-id2'); + expect(meta).toMatchInlineSnapshot(` + Object { + "icon": Object { + "type": "test-file-stub", + }, + "tooltip": "Query assist is available", + "type": "FEATURE", + } + `); + expect(httpMock.get).toBeCalledWith('/api/enhancements/assist/languages', { + query: { dataSourceId: 'mock-data-source-id2' }, + }); + }); + + it('does not send multiple requests for the same data source', async () => { + httpMock.get.mockResolvedValueOnce({ configuredLanguages: ['PPL'] }); + const extension = createQueryAssistExtension(httpMock, dataMock, config); + const metas = await Promise.all( + Array.from({ length: 10 }, () => extension.getDataStructureMeta?.('mock-data-source-id2')) + ); + metas.push(await extension.getDataStructureMeta?.('mock-data-source-id2')); + metas.forEach((meta) => expect(meta?.type).toBe('FEATURE')); + expect(httpMock.get).toBeCalledTimes(1); + }); + it('should render the component if language is supported', async () => { httpMock.get.mockResolvedValueOnce({ configuredLanguages: ['PPL'] }); const extension = createQueryAssistExtension(httpMock, dataMock, config); diff --git a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx index 3b0b12760749..2b86245cc43d 100644 --- a/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx +++ b/src/plugins/query_enhancements/public/query_assist/utils/create_extension.tsx @@ -18,35 +18,41 @@ import { ConfigSchema } from '../../../common/config'; import assistantMark from '../../assets/query_assist_mark.svg'; import { QueryAssistBanner, QueryAssistBar } from '../components'; -/** - * @returns list of query assist supported languages for the given data source. - */ -const getAvailableLanguagesForDataSource = (() => { +const [getAvailableLanguagesForDataSource, clearCache] = (() => { const availableLanguagesByDataSource: Map = new Map(); const pendingRequests: Map> = new Map(); - return async (http: HttpSetup, dataSourceId: string | undefined) => { - const cached = availableLanguagesByDataSource.get(dataSourceId); - if (cached !== undefined) return cached; - - const pendingRequest = pendingRequests.get(dataSourceId); - if (pendingRequest !== undefined) return pendingRequest; - - const languagesPromise = http - .get<{ configuredLanguages: string[] }>(API.QUERY_ASSIST.LANGUAGES, { - query: { dataSourceId }, - }) - .then((response) => response.configuredLanguages) - .catch(() => []) - .finally(() => pendingRequests.delete(dataSourceId)); - pendingRequests.set(dataSourceId, languagesPromise); - - const languages = await languagesPromise; - availableLanguagesByDataSource.set(dataSourceId, languages); - return languages; - }; + return [ + async (http: HttpSetup, dataSourceId: string | undefined) => { + const cached = availableLanguagesByDataSource.get(dataSourceId); + if (cached !== undefined) return cached; + + const pendingRequest = pendingRequests.get(dataSourceId); + if (pendingRequest !== undefined) return pendingRequest; + + const languagesPromise = http + .get<{ configuredLanguages: string[] }>(API.QUERY_ASSIST.LANGUAGES, { + query: { dataSourceId }, + }) + .then((response) => response.configuredLanguages) + .catch(() => []) + .finally(() => pendingRequests.delete(dataSourceId)); + pendingRequests.set(dataSourceId, languagesPromise); + + const languages = await languagesPromise; + availableLanguagesByDataSource.set(dataSourceId, languages); + return languages; + }, + () => { + availableLanguagesByDataSource.clear(); + pendingRequests.clear(); + }, + ]; })(); +// visible for testing +export { clearCache }; + /** * @returns observable list of query assist agent configured languages in the * selected data source. From 3c5a506a9fa68a163a96d3f47a3f076aa1e5a14e Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:33:42 -0700 Subject: [PATCH 259/276] fix: broken dql doc link (#7887) (#7895) (cherry picked from commit 92a9592acc7f353e2b4a69eb6285a1e3de1f7351) Signed-off-by: Yulong Ruan Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../query_string/language_service/get_query_control_links.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx b/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx index 9b92d22ae432..75fcabe27fd4 100644 --- a/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx +++ b/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx @@ -49,7 +49,7 @@ export const QueryControls = (props: { setIsLanguageReferenceOpen(false); }; - const osdDQLDocs = 'https://opensearch.org/docs/2.16/dashboards/dql)'; + const osdDQLDocs = props.services.docLinks?.links.opensearchDashboards.dql.base; const dqlFullName = ( Date: Thu, 29 Aug 2024 10:48:25 +0800 Subject: [PATCH 260/276] Add high level workspace documentation (#5282) (#7906) (cherry picked from commit f62795c1683b3a63d3d0212945abfb346c2b0216) Signed-off-by: Yulong Ruan Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- src/plugins/workspace/README.md | 114 ++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/src/plugins/workspace/README.md b/src/plugins/workspace/README.md index 7e3fff562d82..f79267de7e63 100644 --- a/src/plugins/workspace/README.md +++ b/src/plugins/workspace/README.md @@ -1,4 +1,114 @@ # Workspace +The workspace feature allows users to customize their OpenSearch-Dashboards experience with curated use cases, for example, user can create a workspace particularly for observability use case so that they can concentrate on observability related functionaties. Also, workspace helps users organize visual assets, such as dashboards and visualizations, such assets are isolated by workspace. This makes it a valuable tool for OpenSearch-Dashboards users who want a more precise and flexible workflow. + +## Scopes +The workspace only cares about data stored via saved objects(OSD metadata). The management of data stored by plugins that maintain their independent data stores within their own OpenSearch indexes is OUT OF THE SCOPE. + +## Workspace data model +The Workspace data model defines the fundamental structure for managing isolated environments dedicated to metadata management within OpenSearch Dashboards. + +```typescript +interface Workspace { + id: string + name: string + description?: string + features?: string[] +} +``` + +1. `id`: A unique identifier that distinguishes each workspace. +2. `name`: The name of the workspace. +3. `description`: A description providing context for the workspace. +4. `features`: An array of application IDs associated with the workspace, derived from the plugins registered. These application IDs + are used to filter and display the relevant plugins in the left navigation menu when accessing the workspace. It serves as a visual + mechanism for organizing and presenting features. + + +**Workspace object example** +```typescript +{ + id: "M5NqCu", + name: "Observability team", + description: "Observability team workspace", + features: ["use-case-observability"], +} +``` + +The above object defines a workspace with name `Observability team` that's create with `observability` features by specifying an use case `use-case-observability`. An use case maps to multiple predefined OSD features, only the defined features will be available within the workspace. Use case strings are predefined, there are five types of use cases, except `use-case-all` which all features are available, the other four types of use cases have curated features defined: +1. `use-case-observability` +2. `use-case-security-analytics` +3. `use-case-search` +4. `use-case-analytics` +5. `use-case-all` + +## Associate saved objects with workspaces +Saved objects, such as dashboards, visualizations, and index patterns, form the backbone of data visualization and analysis in OpenSearch Dashboards. +However, as the volume of saved objects grows, keeping them organized becomes increasingly challenging. Grouping saved objects into distinct workspaces, +each serving a specific purpose or team. This association not only simplifies the process of finding and accessing relevant saved objects but also +enhances security and access control (Please ref to this [DOC](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4633) for more details +about access control). + +A new attribute, `workspaces`, is being added to saved objects which type is an array of string. A saved object can be associated with one or multiple workspaces. The saved objects(dashboards, visualizations, etc) will only be showed up in the associated workspaces. + +The follow example shows the dashboard object is associated with workspace which id is `M5NqCu` +```typescript +{ + type: "dashboard", + id: "da123f20-6680-11ee-93fa-df944ec23359", + workspaces: ["M5NqCu"] +} +``` + +Saved object can also be associated with multiple workspaces, this is useful in scenarios where a saved object is relevant to multiple teams, projects, or use cases. + +Consider the following example, where a data source is associated with multiple workspaces: +```typescript +{ + type: "data-source", + id: "da123f20-6680-11ee-93fa-df944ec23359", + workspaces: ["M5NqCu", "", ""] +} +``` +By allowing saved objects to be linked with multiple workspaces, this enables users to share and collaborate on resources across various workspaces(teams). + +## Non-workspace saved objects +While the introduction of workspaces in OSD provides a powerful framework for organizing and managing saved objects, it's important to note that not all saved objects are necessarily associated with workspaces. Some saved objects, by nature or purpose, may exist independently of workspaces. + +For example, the global UI settings object. This object contains configurations and settings that apply globally across OSD, affecting the overall user interface and user experience. These settings are not tied to any specific workspace because they are intended to impact the entire OSD. Such objects won't have `workspaces` attribute. + +The coexistence of workspace-associated saved objects and those without workspace association ensures that OSD strikes a balance between context-specific customization and system-wide consistency. + +## Duplicate saved objects among workspaces +When duplicating objects, it creates hard copies of the objects in the target workspace, regardless of their original workspaces. + +For example, if duplicate the following object to `` +```typescript +{ + type: "visualization", + id: "da123f20-6680-11ee-93fa-df944ec23359", + workspaces: ["M5NqCu", "", ""] +} +``` + +Then a new object will be created with new `id` and associated with `` +```typescript +{ + type: "visualization", + id: "", + workspaces: [""] +} +``` + +### Handling Dependencies +A significant aspect of duplicating saved objects is the handling of dependencies. Many saved objects, particularly visual objects like dashboards and visualizations, often have a hierarchical structure with dependencies. For example, a dashboard may depend on multiple visualizations, and each visualization may rely on specific index pattern objects. + +The duplicating process is not limited to the saved object itself. The user has the flexibility to choose whether or not to duplicate the entire dependency tree. If duplicating the entire dependency hierarchy, all dependencies will be duplicated. For example: +1. If the visualization depends on specific index pattern objects, these index pattern objects will also be duplicated in ``. +2. If the dashboard depends on multiple visualizations, those visualizations and their associated index patterns will be copied as well. + +This ensures that the copied saved object in retains its functionality and context, with all necessary dependencies in place. + +Please note that when multiple data source is enabled, duplicating saved objects to another workspace will not take the data source into consideration. Data source is a special type of object that cannot be duplicated but can only be manually assigned to a workspace. ## Server APIs @@ -317,3 +427,7 @@ POST api/workspaces/_duplicate_saved_objects } ``` +## Appendix +1. The PR the introduce [object access control](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/5083) +2. The [PR](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4633/files) of the design doc for saved object access control +3. Future Vision for Dashboards: [Issue](https://github.com/opensearch-project/OpenSearch-Dashboards/issues/4298) From 667ea69befcbc3969c1a4819fb24bf7e27e2f483 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 15:42:51 +0800 Subject: [PATCH 261/276] fix: only show scrollbar when expanded (#7874) (#7905) (cherry picked from commit a857941a44bf190b199b222a135274ed98d803ae) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../__snapshots__/collapsible_nav_group_enabled.test.tsx.snap | 2 +- .../public/chrome/ui/header/collapsible_nav_group_enabled.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap index 55554ffabf70..11b66bd6d5ae 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap @@ -260,7 +260,7 @@ exports[` should render correctly 2`] = ` class="euiHorizontalRule euiHorizontalRule--full" />
diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx index d8867d973d7d..21ff68f879e2 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx @@ -350,7 +350,7 @@ export function CollapsibleNavGroupEnabled({
Date: Thu, 29 Aug 2024 15:43:08 +0800 Subject: [PATCH 262/276] [Workspace]feat: align essentials use case id (#7873) (#7908) * feat: align essentials use case id * Changeset file for PR #7873 created/updated --------- (cherry picked from commit 4b17e015d7659d12b2bcd83ed952a527c6dd536a) Signed-off-by: SuZhou-Joe Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7873.yml | 2 ++ src/core/utils/default_nav_groups.ts | 2 +- .../public/application/components/home_list_card.test.tsx | 4 ++-- .../components/sample_data/sample_data_card.test.tsx | 2 +- src/plugins/workspace/README.md | 2 +- src/plugins/workspace/common/constants.ts | 2 +- .../components/home_get_start_card/use_case_footer.test.tsx | 4 ++-- .../components/use_case_overview/setup_overview.test.tsx | 6 +++--- .../workspace_form/workspace_detail_form_details.tsx | 6 +++++- src/plugins/workspace/public/plugin.test.ts | 2 +- 10 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 changelogs/fragments/7873.yml diff --git a/changelogs/fragments/7873.yml b/changelogs/fragments/7873.yml new file mode 100644 index 000000000000..ebf0b9e814ed --- /dev/null +++ b/changelogs/fragments/7873.yml @@ -0,0 +1,2 @@ +feat: +- Align essentials use case id ([#7873](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7873)) \ No newline at end of file diff --git a/src/core/utils/default_nav_groups.ts b/src/core/utils/default_nav_groups.ts index 7b3820ccfbd3..7278734ae826 100644 --- a/src/core/utils/default_nav_groups.ts +++ b/src/core/utils/default_nav_groups.ts @@ -9,7 +9,7 @@ import { ChromeNavGroup, NavGroupType } from '../types'; export const ALL_USE_CASE_ID = 'all'; export const OBSERVABILITY_USE_CASE_ID = 'observability'; export const SECURITY_ANALYTICS_USE_CASE_ID = 'security-analytics'; -export const ESSENTIAL_USE_CASE_ID = 'analytics'; +export const ESSENTIAL_USE_CASE_ID = 'essentials'; export const SEARCH_USE_CASE_ID = 'search'; const defaultNavGroups = { diff --git a/src/plugins/home/public/application/components/home_list_card.test.tsx b/src/plugins/home/public/application/components/home_list_card.test.tsx index f5916e4b74e7..cbad31f15993 100644 --- a/src/plugins/home/public/application/components/home_list_card.test.tsx +++ b/src/plugins/home/public/application/components/home_list_card.test.tsx @@ -74,7 +74,7 @@ describe('Register HomeListCardToPages', () => { expect(contentManagementStartMock.registerContentProvider).toHaveBeenCalledTimes(4); let whatsNewCall = registerContentProviderFn.mock.calls[0]; - expect(whatsNewCall[0].getTargetArea()).toEqual('analytics_overview/service_cards'); + expect(whatsNewCall[0].getTargetArea()).toEqual('essentials_overview/service_cards'); expect(whatsNewCall[0].getContent()).toMatchInlineSnapshot(` Object { "id": "whats_new", @@ -86,7 +86,7 @@ describe('Register HomeListCardToPages', () => { `); let learnOpenSearchCall = registerContentProviderFn.mock.calls[1]; - expect(learnOpenSearchCall[0].getTargetArea()).toEqual('analytics_overview/service_cards'); + expect(learnOpenSearchCall[0].getTargetArea()).toEqual('essentials_overview/service_cards'); expect(learnOpenSearchCall[0].getContent()).toMatchInlineSnapshot(` Object { "id": "learn_opensearch_new", diff --git a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx index 44d7a4b6f007..df93e5cd2a4b 100644 --- a/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx +++ b/src/plugins/home/public/application/components/sample_data/sample_data_card.test.tsx @@ -19,7 +19,7 @@ describe('Sample data card', () => { it('should call the getTargetArea function with the correct arguments', () => { registerSampleDataCard(contentManagement, coreStart); const call = registerContentProviderMock.mock.calls[0]; - expect(call[0].getTargetArea()).toEqual(['analytics_overview/get_started']); + expect(call[0].getTargetArea()).toEqual(['essentials_overview/get_started']); expect(call[0].getContent()).toMatchInlineSnapshot(` Object { "cardProps": Object { diff --git a/src/plugins/workspace/README.md b/src/plugins/workspace/README.md index f79267de7e63..9bc8fc324fac 100644 --- a/src/plugins/workspace/README.md +++ b/src/plugins/workspace/README.md @@ -38,7 +38,7 @@ The above object defines a workspace with name `Observability team` that's creat 1. `use-case-observability` 2. `use-case-security-analytics` 3. `use-case-search` -4. `use-case-analytics` +4. `use-case-essentials` 5. `use-case-all` ## Associate saved objects with workspaces diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index 735c253fd0c0..d6009bed1482 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -97,7 +97,7 @@ export const WORKSPACE_USE_CASES = Object.freeze({ ] as string[], }, essentials: { - id: 'analytics', + id: 'essentials', title: i18n.translate('workspace.usecase.essentials.title', { defaultMessage: 'Essentials', }), diff --git a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx index 914fa4751ff8..5fbadff102ca 100644 --- a/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx +++ b/src/plugins/workspace/public/components/home_get_start_card/use_case_footer.test.tsx @@ -47,7 +47,7 @@ describe('UseCaseFooter', () => { it('renders create workspace button for admin when no workspaces within use case exist', () => { const { getByTestId } = render( { it('renders create workspace button for non-admin when no workspaces within use case exist', () => { const { getByTestId } = render( { const call = registerPageMock.mock.calls[0]; expect(call[0]).toMatchInlineSnapshot(` Object { - "id": "analytics_overview", + "id": "essentials_overview", "sections": Array [ Object { "id": "service_cards", @@ -71,7 +71,7 @@ describe('Setup use case overview', () => { expect(calls.length).toBe(3); const firstCall = calls[0]; - expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"analytics_overview/get_started"`); + expect(firstCall[0].getTargetArea()).toMatchInlineSnapshot(`"essentials_overview/get_started"`); expect(firstCall[0].getContent()).toMatchInlineSnapshot(` Object { "cardProps": Object { @@ -99,7 +99,7 @@ describe('Setup use case overview', () => { const call = registerPageMock.mock.calls[0]; expect(call[0]).toMatchInlineSnapshot(` Object { - "id": "analytics_overview", + "id": "essentials_overview", "sections": Array [ Object { "id": "service_cards", diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx index 3de52f3aabff..b72181ae1114 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form_details.tsx @@ -64,7 +64,11 @@ export const WorkspaceDetailFormDetails = ({ // Essential can be changed to other use cases; // Analytics (all) cannot be changed back to a single use case; // Other use cases can only be changed to Analytics (all) use case. - return currentUseCase === 'analytics' || id === 'all' || id === currentUseCase; + return ( + currentUseCase === DEFAULT_NAV_GROUPS.essentials.id || + id === DEFAULT_NAV_GROUPS.all.id || + id === currentUseCase + ); }) .map((useCase) => ({ value: useCase.id, diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index c6bc16e1c939..cf0f67f89829 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -284,7 +284,7 @@ describe('Workspace plugin', () => { expect(setupMock.application.register).toHaveBeenCalledWith( expect.objectContaining({ - id: 'analytics_overview', + id: 'essentials_overview', }) ); }); From e886b277777e2da69b0dc337762fb129ad8b1e46 Mon Sep 17 00:00:00 2001 From: "Qingyang(Abby) Hu" Date: Thu, 29 Aug 2024 15:36:30 -0700 Subject: [PATCH 263/276] [discover] Query editor UI clean up (#7896) (#7902) * follow up * address comments * Changeset file for PR #7896 created/updated --------- Signed-off-by: abbyhu2000 Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7896.yml | 2 + .../default_language_reference.tsx | 77 ++++++++ .../get_query_control_links.tsx | 169 +----------------- .../language_service/language_service.ts | 16 +- .../public/ui/query_editor/editors/shared.tsx | 11 +- .../public/ui/query_editor/query_editor.tsx | 44 +++-- .../query_enhancements/public/plugin.tsx | 13 +- .../query_editor}/flyout_containers.tsx | 0 .../query_editor}/ppl_docs/commands/dedup.ts | 0 .../query_editor}/ppl_docs/commands/eval.ts | 0 .../query_editor}/ppl_docs/commands/fields.ts | 0 .../query_editor}/ppl_docs/commands/head.ts | 0 .../query_editor}/ppl_docs/commands/index.ts | 0 .../query_editor}/ppl_docs/commands/parse.ts | 0 .../query_editor}/ppl_docs/commands/rare.ts | 0 .../query_editor}/ppl_docs/commands/rename.ts | 0 .../query_editor}/ppl_docs/commands/search.ts | 0 .../query_editor}/ppl_docs/commands/sort.ts | 0 .../query_editor}/ppl_docs/commands/stats.ts | 0 .../query_editor}/ppl_docs/commands/syntax.ts | 0 .../query_editor}/ppl_docs/commands/top.ts | 0 .../query_editor}/ppl_docs/commands/where.ts | 0 .../ppl_docs/functions/condition.ts | 0 .../ppl_docs/functions/datetime.ts | 0 .../ppl_docs/functions/full_text_search.ts | 0 .../query_editor}/ppl_docs/functions/index.ts | 0 .../query_editor}/ppl_docs/functions/math.ts | 0 .../ppl_docs/functions/string.ts | 0 .../public/query_editor}/ppl_docs/groups.tsx | 0 .../ppl_docs/language_structure/datatypes.ts | 0 .../language_structure/identifiers.ts | 0 .../ppl_docs/language_structure/index.ts | 0 .../query_editor}/ppl_docs/overview.tsx | 0 .../query_editor}/ppl_reference_flyout.tsx | 0 .../query_editor/query_language_reference.tsx | 50 ++++++ .../query_editor}/sql_reference_flyout.tsx | 0 36 files changed, 192 insertions(+), 190 deletions(-) create mode 100644 changelogs/fragments/7896.yml create mode 100644 src/plugins/data/public/query/query_string/language_service/default_language_reference.tsx rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/flyout_containers.tsx (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/dedup.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/eval.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/fields.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/head.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/index.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/parse.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/rare.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/rename.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/search.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/sort.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/stats.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/syntax.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/top.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/commands/where.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/functions/condition.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/functions/datetime.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/functions/full_text_search.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/functions/index.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/functions/math.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/functions/string.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/groups.tsx (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/language_structure/datatypes.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/language_structure/identifiers.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/language_structure/index.ts (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_docs/overview.tsx (100%) rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/ppl_reference_flyout.tsx (100%) create mode 100644 src/plugins/query_enhancements/public/query_editor/query_language_reference.tsx rename src/plugins/{data/public/query/query_string/language_service => query_enhancements/public/query_editor}/sql_reference_flyout.tsx (100%) diff --git a/changelogs/fragments/7896.yml b/changelogs/fragments/7896.yml new file mode 100644 index 000000000000..cfac5d806ff4 --- /dev/null +++ b/changelogs/fragments/7896.yml @@ -0,0 +1,2 @@ +fix: +- Query editor UI clean up ([#7896](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7896)) \ No newline at end of file diff --git a/src/plugins/data/public/query/query_string/language_service/default_language_reference.tsx b/src/plugins/data/public/query/query_string/language_service/default_language_reference.tsx new file mode 100644 index 000000000000..56dda2550426 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/default_language_reference.tsx @@ -0,0 +1,77 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { i18n } from '@osd/i18n'; + +import { EuiButtonIcon, EuiLink, EuiPopover, EuiPopoverTitle, EuiText } from '@elastic/eui'; + +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import { IDataPluginServices } from '../../../types'; +import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; + +export const DefaultLanguageReference = () => { + const opensearchDashboards = useOpenSearchDashboards(); + const [isLanguageReferenceOpen, setIsLanguageReferenceOpen] = React.useState(false); + const osdDQLDocs = opensearchDashboards.services.docLinks?.links.opensearchDashboards.dql.base; + const dqlFullName = ( + + ); + + const button = ( +
+ setIsLanguageReferenceOpen(!isLanguageReferenceOpen)} + /> +
+ ); + + return ( + setIsLanguageReferenceOpen(false)} + panelPaddingSize="s" + anchorPosition="downLeft" + anchorClassName="euiFormControlLayout__append" + > + + + +
+ +

+ + {dqlFullName} + + ), + }} + /> +

+
+
+
+ ); +}; + +export const createDefaultLanguageReference = () => { + return ; +}; diff --git a/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx b/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx index 75fcabe27fd4..80898d5468b7 100644 --- a/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx +++ b/src/plugins/data/public/query/query_string/language_service/get_query_control_links.tsx @@ -3,170 +3,17 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { i18n } from '@osd/i18n'; -import React, { useState } from 'react'; -import { - EuiButtonIcon, - EuiFlexGroup, - EuiFlexItem, - EuiLink, - EuiPopoverTitle, - EuiText, - EuiWrappingPopover, -} from '@elastic/eui'; -import ReactDOM from 'react-dom'; -import { FormattedMessage } from 'react-intl'; -import { - OpenSearchDashboardsContextProvider, - toMountPoint, -} from '../../../../../opensearch_dashboards_react/public'; -import { IDataPluginServices } from '../../../types'; -import { PPLReferenceFlyout } from './ppl_reference_flyout'; - -export interface QueryControl { - id: string; - label: string; - testId: string; - ariaLabel: string; - run: (anchorElement: HTMLElement) => void; - iconType: string; -} - -export const QueryControls = (props: { - services: IDataPluginServices; - queryLanguage: string; - onToggleCollapse: () => void; - savedQueryManagement?: any; - additionalControls?: QueryControl[]; -}) => { - const [isCollapsed, setIsCollapsed] = useState(false); - const [isLanguageReferenceOpen, setIsLanguageReferenceOpen] = useState(false); - - const languageReferenceContainer = document.createElement('div'); - - const onCloseLanguageReference = () => { - ReactDOM.unmountComponentAtNode(languageReferenceContainer); - setIsLanguageReferenceOpen(false); - }; - - const osdDQLDocs = props.services.docLinks?.links.opensearchDashboards.dql.base; - const dqlFullName = ( - - ); - - const languageReference: QueryControl = { - id: 'languageReference', - label: i18n.translate('discover.queryControls.languageReference', { - defaultMessage: 'Open', - }), - testId: 'languageReference', - ariaLabel: i18n.translate('discover.queryControls.languageReference', { - defaultMessage: `Language Reference`, - }), - run: async (anchorElement) => { - if (props.queryLanguage === 'PPL' || props.queryLanguage === 'SQL') { - const flyoutSession = props.services.overlays!.openFlyout( - toMountPoint( - - flyoutSession?.close?.().then()} - makeUrl={(searchId: any) => `#/view/${encodeURIComponent(searchId)}`} - /> - - ) - ); - } else { - if (isLanguageReferenceOpen) { - onCloseLanguageReference(); - return; - } - - setIsLanguageReferenceOpen(true); - document.body.appendChild(languageReferenceContainer); - - const element = ( - - - - -
- -

- - {dqlFullName} - - ), - }} - /> -

-
-
-
- ); - - ReactDOM.render(element, languageReferenceContainer); - } - }, - iconType: 'iInCircle', - }; - - const languageToggle: QueryControl = { - id: 'languageToggle', - label: i18n.translate('discover.queryControls.languageToggle', { - defaultMessage: 'Toggle', - }), - testId: 'languageToggle', - ariaLabel: i18n.translate('discover.queryControls.languageToggle', { - defaultMessage: `Language Toggle`, - }), - run: () => { - setIsCollapsed(!isCollapsed); - props.onToggleCollapse(); - }, - iconType: isCollapsed ? 'expand' : 'minimize', - }; - - const queryControls = - props.queryLanguage === 'PPL' || props.queryLanguage === 'SQL' - ? [languageReference, languageToggle] - : [languageReference]; - - if (props.additionalControls) { - queryControls.push(...props.additionalControls); - } +import React from 'react'; +import { EuiFlexItem } from '@elastic/eui'; +export const QueryControls = (props: { queryControls: React.ReactElement[] }) => { return ( - - {queryControls.map((queryControl) => ( - - queryControl.run(event.currentTarget)} - /> + <> + {props.queryControls.map((queryControl, idx) => ( + + {queryControl} ))} - {props.savedQueryManagement} - + ); }; diff --git a/src/plugins/data/public/query/query_string/language_service/language_service.ts b/src/plugins/data/public/query/query_string/language_service/language_service.ts index 923838c26bb2..113a85e25e10 100644 --- a/src/plugins/data/public/query/query_string/language_service/language_service.ts +++ b/src/plugins/data/public/query/query_string/language_service/language_service.ts @@ -14,6 +14,7 @@ import { UiEnhancements, } from '../../../ui'; import { DataStorage, setOverrides as setFieldOverrides } from '../../../../common'; +import { createDefaultLanguageReference } from './default_language_reference'; export class LanguageService { private languages: Map = new Map(); @@ -27,10 +28,6 @@ export class LanguageService { this.queryEditorExtensionMap = {}; } - public createDefaultQueryEditor() { - return createEditor(SingleLineInput, SingleLineInput, DQLBody); - } - public __enhance = (enhancements: UiEnhancements) => { if (enhancements.queryEditorExtension) { this.queryEditorExtensionMap[enhancements.queryEditorExtension.id] = @@ -38,11 +35,20 @@ export class LanguageService { } }; + public createDefaultLanguageReference = () => { + return createDefaultLanguageReference(); + }; + /** * Registers default handlers for index patterns and indices. */ private registerDefaultLanguages() { - const defaultEditor = createEditor(SingleLineInput, SingleLineInput, DQLBody); + const defaultEditor = createEditor( + SingleLineInput, + SingleLineInput, + [this.createDefaultLanguageReference()], + DQLBody + ); this.registerLanguage(getDQLLanguageConfig(this.defaultSearchInterceptor, defaultEditor)); this.registerLanguage(getLuceneLanguageConfig(this.defaultSearchInterceptor, defaultEditor)); } diff --git a/src/plugins/data/public/ui/query_editor/editors/shared.tsx b/src/plugins/data/public/ui/query_editor/editors/shared.tsx index 1da3b2c880c3..6608b95042de 100644 --- a/src/plugins/data/public/ui/query_editor/editors/shared.tsx +++ b/src/plugins/data/public/ui/query_editor/editors/shared.tsx @@ -21,18 +21,11 @@ type CollapsedComponent = React.ComponentType; type ExpandedComponent = React.ComponentType | null; type BodyComponent = React.ComponentType; -export interface Editor { - TopBar: { - Collapsed: CollapsedComponent; - Expanded: ExpandedComponent; - }; - Body: BodyComponent
; -} - export interface EditorInstance { TopBar: { Collapsed: () => React.ReactElement; Expanded: (() => React.ReactElement) | null; + Controls: React.ReactElement[]; }; Body: () => React.ReactElement; } @@ -44,6 +37,7 @@ export function createEditor< >( collapsed: CollapsedComponent, expanded: ExpandedComponent, + controls: React.ReactElement[], body: BodyComponent ) { return ( @@ -54,6 +48,7 @@ export function createEditor< TopBar: { Collapsed: () => React.createElement(collapsed, collapsedProps), Expanded: expanded ? () => React.createElement(expanded, expandedProps) : null, + Controls: controls, }, Body: () => React.createElement(body, bodyProps), }); diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index 619184883220..3c9e81b4824d 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -3,7 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiCompressedFieldText, EuiText, PopoverAnchorPosition } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; + +import { + EuiButtonIcon, + EuiCompressedFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiText, + PopoverAnchorPosition, +} from '@elastic/eui'; import classNames from 'classnames'; import { isEqual } from 'lodash'; import React, { Component, createRef, RefObject } from 'react'; @@ -293,21 +302,24 @@ export default class QueryEditorUI extends Component { }; }; - public onToggleCollapse = () => { - this.setState({ isCollapsed: !this.state.isCollapsed }); - }; - - private renderQueryControls = () => { + private renderToggleIcon = () => { return ( - + + this.setIsCollapsed(!this.state.isCollapsed)} + /> + ); }; + private renderQueryControls = (queryControls: React.ReactElement[]) => { + return ; + }; + public render() { const className = classNames(this.props.className); @@ -416,7 +428,13 @@ export default class QueryEditorUI extends Component { : languageEditor.TopBar.Expanded && languageEditor.TopBar.Expanded()} {languageSelector} -
{this.renderQueryControls()}
+
+ + {this.renderQueryControls(languageEditor.TopBar.Controls)} + {!languageEditor.TopBar.Expanded && this.renderToggleIcon()} + {this.props.savedQueryManagement} + +
) { + startServices.then(([coreStart]) => { + this.coreStart = coreStart; + this.overLaysService = coreStart.overlays; + }); + } + + public createPPLLanguageReference() { + const button = ( + { + const flyoutSession = this.overLaysService!.openFlyout( + toMountPoint( + + flyoutSession?.close()} + makeUrl={(searchId: any) => `#/view/${encodeURIComponent(searchId)}`} + /> + + ) + ); + }} + /> + ); + return button; + } +} diff --git a/src/plugins/data/public/query/query_string/language_service/sql_reference_flyout.tsx b/src/plugins/query_enhancements/public/query_editor/sql_reference_flyout.tsx similarity index 100% rename from src/plugins/data/public/query/query_string/language_service/sql_reference_flyout.tsx rename to src/plugins/query_enhancements/public/query_editor/sql_reference_flyout.tsx From 51b5c64912db041c77642c8b06ccbdcc512ce324 Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Thu, 29 Aug 2024 16:17:02 -0700 Subject: [PATCH 264/276] [Backport 2.x] [discover] registered languages interceptor clean up and aggs (#7870) (#7900) * [discover] registered languages interceptor clean up and aggs (#7870) Clean up interceptor and strategies. Re-add aggregations working for PPL language Signed-off-by: Kawika Avilla (cherry picked from commit 9b8266f178270e0e93aa82fa1e2f9c8c15737238) * fix conflict Signed-off-by: Kawika Avilla --------- Signed-off-by: Kawika Avilla --- changelogs/fragments/7870.yml | 2 + src/plugins/data/common/data_frames/utils.ts | 253 ++---------------- .../dataset_service/lib/index_pattern_type.ts | 3 + .../dataset_service/lib/index_type.ts | 9 +- .../query_enhancements/common/constants.ts | 4 + .../query_enhancements/common/types.ts | 13 +- .../query_enhancements/common/utils.ts | 19 +- .../public/datasets/s3_handler.ts | 12 +- .../public/search/ppl_search_interceptor.ts | 168 +++++------- .../public/search/sql_search_interceptor.ts | 141 +++------- .../query_enhancements/server/routes/index.ts | 45 ++++ .../server/search/ppl_search_strategy.ts | 46 +--- .../server/search/sql_search_strategy.test.ts | 81 +++++- .../server/search/sql_search_strategy.ts | 29 +- 14 files changed, 308 insertions(+), 517 deletions(-) create mode 100644 changelogs/fragments/7870.yml diff --git a/changelogs/fragments/7870.yml b/changelogs/fragments/7870.yml new file mode 100644 index 000000000000..cb0c33dfcb39 --- /dev/null +++ b/changelogs/fragments/7870.yml @@ -0,0 +1,2 @@ +fix: +- Clean up language search interceptors and fix aggs for PPL ([#7870](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7870)) \ No newline at end of file diff --git a/src/plugins/data/common/data_frames/utils.ts b/src/plugins/data/common/data_frames/utils.ts index 8c9f63b0f0d3..fdee757bfabb 100644 --- a/src/plugins/data/common/data_frames/utils.ts +++ b/src/plugins/data/common/data_frames/utils.ts @@ -8,7 +8,6 @@ import datemath from '@opensearch/datemath'; import { DATA_FRAME_TYPES, DataFrameAggConfig, - DataFrameBucketAgg, IDataFrame, IDataFrameWithAggs, IDataFrameResponse, @@ -17,139 +16,7 @@ import { } from './types'; import { IFieldType } from './fields'; import { IndexPatternFieldMap, IndexPatternSpec } from '../index_patterns'; -import { IOpenSearchDashboardsSearchRequest } from '../search'; -import { GetAggTypeFn, GetDataFrameAggQsFn, Query, TimeRange } from '../types'; - -/** - * Returns the raw data frame from the search request. - * - * @param searchRequest - search request object. - * @returns dataframe - */ -export const getRawDataFrame = (searchRequest: IOpenSearchDashboardsSearchRequest) => { - return searchRequest.params?.body?.df; -}; - -/** - * Returns the raw query string from the search request. - * Gets current state query if exists, otherwise gets the initial query. - * - * @param searchRequest - search request object - * @returns query string - */ -export const getRawQueryString = ( - searchRequest: IOpenSearchDashboardsSearchRequest -): string | undefined => { - return ( - searchRequest.params?.body?.query?.queries[1]?.query ?? - searchRequest.params?.body?.query?.queries[0]?.query - ); -}; - -/** - * Returns the raw aggregations from the search request. - * - * @param searchRequest - search request object - * @returns aggregations - */ -export const getRawAggs = (searchRequest: IOpenSearchDashboardsSearchRequest) => { - return searchRequest.params?.body?.aggs; -}; - -/** - * Returns the unique values for raw aggregations. This is used - * with `other-filter` aggregation. To get the values that were not - * included in the aggregation response prior to this request. - * - * @param rawAggs - raw aggregations object - * @returns object containing the field and its unique values - */ -export const getUniqueValuesForRawAggs = (rawAggs: Record) => { - const filters = rawAggs.filters?.filters?.['']?.bool?.must_not; - if (!filters || !Array.isArray(filters)) { - return null; - } - const values: unknown[] = []; - let field: string | undefined; - - filters.forEach((agg: any) => { - Object.values(agg).forEach((aggValue) => { - Object.entries(aggValue as Record).forEach(([key, value]) => { - field = key; - values.push(value); - }); - }); - }); - - return { field, values }; -}; - -/** - * Returns the aggregation configuration for raw aggregations. - * Aggregations are nested objects, so this function recursively - * builds an object that is easier to work with. - * - * @param rawAggs - raw aggregations object - * @returns aggregation configuration - */ -export const getAggConfigForRawAggs = (rawAggs: Record): DataFrameAggConfig | null => { - const aggConfig: DataFrameAggConfig = { id: '', type: '' }; - - Object.entries(rawAggs).forEach(([aggKey, agg]) => { - aggConfig.id = aggKey; - Object.entries(agg as Record).forEach(([name, value]) => { - if (name === 'aggs') { - aggConfig.aggs = {}; - Object.entries(value as Record).forEach(([subAggKey, subRawAgg]) => { - const subAgg = getAggConfigForRawAggs(subRawAgg as Record); - if (subAgg) { - aggConfig.aggs![subAgg.id] = { ...subAgg, id: subAggKey }; - } - }); - } else { - aggConfig.type = name; - Object.assign(aggConfig, { [name]: value }); - } - }); - }); - - return aggConfig; -}; - -/** - * Returns the aggregation configuration. - * - * @param searchRequest - search request object - * @param aggConfig - aggregation configuration object - * @param getAggTypeFn - function to get the aggregation type from the aggsService - * @returns aggregation configuration - */ -export const getAggConfig = ( - searchRequest: IOpenSearchDashboardsSearchRequest, - aggConfig: Partial = {}, - getAggTypeFn: GetAggTypeFn -): DataFrameAggConfig => { - const rawAggs = getRawAggs(searchRequest); - Object.entries(rawAggs).forEach(([aggKey, agg]) => { - aggConfig.id = aggKey; - Object.entries(agg as Record).forEach(([name, value]) => { - if (name === 'aggs' && value) { - aggConfig.aggs = {}; - Object.entries(value as Record).forEach(([subAggKey, subRawAgg]) => { - const subAgg = getAggConfigForRawAggs(subRawAgg as Record); - if (subAgg) { - aggConfig.aggs![subAgg.id] = { ...subAgg, id: subAggKey }; - } - }); - } else { - aggConfig.type = getAggTypeFn(name)?.type ?? name; - Object.assign(aggConfig, { [name]: value }); - } - }); - }); - - return aggConfig as DataFrameAggConfig; -}; +import { TimeRange } from '../types'; /** * Converts the data frame response to a search response. @@ -199,61 +66,35 @@ export const convertResult = (response: IDataFrameResponse): SearchResponse if (data.hasOwnProperty('aggs')) { const dataWithAggs = data as IDataFrameWithAggs; if (!dataWithAggs.aggs) { - // TODO: MQL best guess, get timestamp field and caculate it here return searchResponse; } - searchResponse.aggregations = Object.entries(dataWithAggs.aggs).reduce( - (acc: Record, [id, value]) => { - const aggConfig = dataWithAggs.meta?.aggs; - if (id === 'other-filter') { - const buckets = value as DataFrameBucketAgg[]; - buckets.forEach((bucket) => { - const bucketValue = bucket.value; - searchResponse.hits.total += bucketValue; - }); - acc[id] = { - buckets: [{ '': { doc_count: 0 } }], - }; - return acc; - } - if (aggConfig && aggConfig.type === 'buckets') { - const buckets = value as DataFrameBucketAgg[]; - acc[id] = { - buckets: buckets.map((bucket) => { - const bucketValue = bucket.value; - searchResponse.hits.total += bucketValue; - return { - key_as_string: bucket.key, - key: (aggConfig as DataFrameAggConfig).date_histogram - ? new Date(bucket.key).getTime() - : bucket.key, - doc_count: bucketValue, - }; - }), - }; - return acc; - } - acc[id] = Array.isArray(value) ? value[0] : value; - return acc; - }, - {} - ); + searchResponse.aggregations = {}; + + const aggConfig = dataWithAggs.meta; + Object.entries(dataWithAggs.aggs).forEach(([id, value]) => { + if (aggConfig && aggConfig.date_histogram) { + const buckets = value as Array<{ key: string; value: number }>; + searchResponse.aggregations[id] = { + buckets: buckets.map((bucket) => { + const timestamp = new Date(bucket.key).getTime(); + searchResponse.hits.total += bucket.value; + return { + key_as_string: bucket.key, + key: timestamp, + doc_count: bucket.value, + }; + }), + }; + } else { + // Handle other aggregation types here if needed + searchResponse.aggregations[id] = value; + } + }); } return searchResponse; }; -/** - * Formats the field value. - * - * @param field - field object - * @param value - value to format - * @returns formatted value - */ -export const formatFieldValue = (field: IFieldType | Partial, value: any): any => { - return field.format && field.format.convert ? field.format.convert(value) : value; -}; - /** * Returns the field type. This function is used to determine the field type so that can * be used by the rest of the application. The field type must map to a OsdFieldType @@ -372,54 +213,6 @@ export const createDataFrame = (partial: PartialDataFrame): IDataFrame | IDataFr }; }; -/** - * Updates the data frame metadata. Metadata is used to store the aggregation configuration. - * It also stores the query string used to fetch the data frame aggregations. - * - * @param params - { dataFrame, qs, aggConfig, timeField, timeFilter, getAggQsFn } - */ -export const updateDataFrameMeta = ({ - dataFrame, - query, - aggConfig, - timeField, - timeFilter, - getAggQsFn, -}: { - dataFrame: IDataFrame; - query: Query; - aggConfig: DataFrameAggConfig; - timeField: any; - timeFilter: string; - getAggQsFn: GetDataFrameAggQsFn; -}) => { - dataFrame.meta = { - ...dataFrame?.meta, - aggs: aggConfig, - aggsQs: { - [aggConfig.id]: getAggQsFn({ - query, - aggConfig, - timeField, - timeFilter, - }), - }, - }; - - if (aggConfig.aggs) { - const subAggs = aggConfig.aggs as Record; - for (const [key, subAgg] of Object.entries(subAggs)) { - const subAggConfig: Record = { [key]: subAgg }; - dataFrame.meta.aggsQs[subAgg.id] = getAggQsFn({ - query, - aggConfig: subAggConfig as DataFrameAggConfig, - timeField, - timeFilter, - }); - } - } -}; - /** * Converts a data frame to index pattern spec which can be used to create an index pattern. * diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts index e549a5abdf3d..1034850c41ba 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts @@ -12,6 +12,7 @@ import { Dataset, IIndexPattern, DATA_STRUCTURE_META_TYPES, + DataStructureCustomMeta, } from '../../../../../common'; import { DatasetTypeConfig } from '../types'; import { getIndexPatterns } from '../../../../services'; @@ -27,10 +28,12 @@ export const indexPatternTypeConfig: DatasetTypeConfig = { toDataset: (path) => { const pattern = path[path.length - 1]; + const patternMeta = pattern.meta as DataStructureCustomMeta; return { id: pattern.id, title: pattern.title, type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + timeFieldName: patternMeta?.timeFieldName, dataSource: pattern.parent ? { id: pattern.parent.id, diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts index 6dfcdc46df49..fe18afbd2e76 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts @@ -5,7 +5,12 @@ import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; import { map } from 'rxjs/operators'; -import { DEFAULT_DATA, DataStructure, Dataset } from '../../../../../common'; +import { + DEFAULT_DATA, + DataStructure, + DataStructureCustomMeta, + Dataset, +} from '../../../../../common'; import { DatasetTypeConfig } from '../types'; import { getSearchService, getIndexPatterns } from '../../../../services'; import { injectMetaToDataStructures } from './utils'; @@ -29,11 +34,13 @@ export const indexTypeConfig: DatasetTypeConfig = { toDataset: (path) => { const index = path[path.length - 1]; const dataSource = path.find((ds) => ds.type === 'DATA_SOURCE'); + const indexMeta = index.meta as DataStructureCustomMeta; return { id: index.id, title: index.title, type: DEFAULT_DATA.SET_TYPES.INDEX, + timeFieldName: indexMeta?.timeFieldName, dataSource: dataSource ? { id: dataSource.id, diff --git a/src/plugins/query_enhancements/common/constants.ts b/src/plugins/query_enhancements/common/constants.ts index 57316efdf5d2..36dcd27ffa00 100644 --- a/src/plugins/query_enhancements/common/constants.ts +++ b/src/plugins/query_enhancements/common/constants.ts @@ -8,6 +8,10 @@ export const PLUGIN_NAME = 'queryEnhancements'; export const BASE_API = '/api/enhancements'; +export const DATASET = { + S3: 'S3', +}; + export const SEARCH_STRATEGY = { PPL: 'ppl', PPL_RAW: 'pplraw', diff --git a/src/plugins/query_enhancements/common/types.ts b/src/plugins/query_enhancements/common/types.ts index c98ca0284969..7efb0d9f3d13 100644 --- a/src/plugins/query_enhancements/common/types.ts +++ b/src/plugins/query_enhancements/common/types.ts @@ -6,7 +6,18 @@ import { CoreSetup } from 'opensearch-dashboards/public'; import { Observable } from 'rxjs'; -export interface FetchDataFrameContext { +export interface QueryAggConfig { + [key: string]: { + field?: string; + fixed_interval?: string; + calendar_interval?: string; + min_doc_count?: number; + time_zone?: string; + [x: number]: string; + }; +} + +export interface EnhancedFetchContext { http: CoreSetup['http']; path: string; signal?: AbortSignal; diff --git a/src/plugins/query_enhancements/common/utils.ts b/src/plugins/query_enhancements/common/utils.ts index 208256bd4dd4..bdb8740e4e48 100644 --- a/src/plugins/query_enhancements/common/utils.ts +++ b/src/plugins/query_enhancements/common/utils.ts @@ -6,7 +6,7 @@ import { IDataFrame, Query } from 'src/plugins/data/common'; import { Observable, Subscription, from, throwError, timer } from 'rxjs'; import { catchError, concatMap, last, takeWhile, tap } from 'rxjs/operators'; -import { FetchDataFrameContext, FetchFunction } from './types'; +import { EnhancedFetchContext, FetchFunction, QueryAggConfig } from './types'; export const formatDate = (dateString: string) => { const date = new Date(dateString); @@ -133,7 +133,20 @@ export const handleDataFrameError = (response: any) => { } }; -export const fetchDataFrame = (context: FetchDataFrameContext, query: Query, df: IDataFrame) => { +export const fetch = (context: EnhancedFetchContext, query: Query, aggConfig?: QueryAggConfig) => { + const { http, path, signal } = context; + const body = JSON.stringify({ query: { ...query, format: 'jdbc' }, aggConfig }); + return from( + http.fetch({ + method: 'POST', + path, + body, + signal, + }) + ).pipe(tap(handleDataFrameError)); +}; + +export const fetchDataFrame = (context: EnhancedFetchContext, query: Query, df: IDataFrame) => { const { http, path, signal } = context; const body = JSON.stringify({ query: { ...query, format: 'jdbc' }, df }); return from( @@ -146,7 +159,7 @@ export const fetchDataFrame = (context: FetchDataFrameContext, query: Query, df: ).pipe(tap(handleDataFrameError)); }; -export const fetchDataFramePolling = (context: FetchDataFrameContext, df: IDataFrame) => { +export const fetchDataFramePolling = (context: EnhancedFetchContext, df: IDataFrame) => { const { http, path, signal } = context; const queryId = df.meta?.queryId; const dataSourceId = df.meta?.queryConfig?.dataSourceId; diff --git a/src/plugins/query_enhancements/public/datasets/s3_handler.ts b/src/plugins/query_enhancements/public/datasets/s3_handler.ts index ce18662146bc..2613f016143f 100644 --- a/src/plugins/query_enhancements/public/datasets/s3_handler.ts +++ b/src/plugins/query_enhancements/public/datasets/s3_handler.ts @@ -6,13 +6,13 @@ import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; import { DataStructure, Dataset, DatasetField } from 'src/plugins/data/common'; import { DatasetTypeConfig } from 'src/plugins/data/public'; +import { DATASET } from '../../common'; const S3_ICON = 'visTable'; -const S3_ID = 'S3'; export const s3TypeConfig: DatasetTypeConfig = { - id: S3_ID, - title: S3_ID, + id: DATASET.S3, + title: DATASET.S3, meta: { icon: { type: S3_ICON }, tooltip: 'S3 Data Source', @@ -20,12 +20,12 @@ export const s3TypeConfig: DatasetTypeConfig = { toDataset: (path: DataStructure[]): Dataset => { const s3 = path[path.length - 1]; - const dataSource = path.find((ds) => ds.type === S3_ID); + const dataSource = path.find((ds) => ds.type === DATASET.S3); return { id: s3.id, title: s3.title, - type: S3_ID, + type: DATASET.S3, dataSource: dataSource ? { id: dataSource.id, @@ -42,7 +42,7 @@ export const s3TypeConfig: DatasetTypeConfig = { ): Promise => { const dataStructure = path[path.length - 1]; switch (dataStructure.type) { - case S3_ID: + case DATASET.S3: return { ...dataStructure, columnHeader: 'Connections', diff --git a/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts b/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts index 3a5edd67ca7f..4618945a35f7 100644 --- a/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts +++ b/src/plugins/query_enhancements/public/search/ppl_search_interceptor.ts @@ -6,14 +6,7 @@ import { trimEnd } from 'lodash'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; -import { - DataFrameAggConfig, - getRawDataFrame, - formatTimePickerDate, - getUniqueValuesForRawAggs, - updateDataFrameMeta, - Query, -} from '../../../data/common'; +import { formatTimePickerDate, Query } from '../../../data/common'; import { DataPublicPluginStart, IOpenSearchDashboardsSearchRequest, @@ -25,10 +18,10 @@ import { import { formatDate, SEARCH_STRATEGY, - removeKeyword, API, - FetchDataFrameContext, - fetchDataFrame, + EnhancedFetchContext, + fetch, + QueryAggConfig, } from '../../common'; import { QueryEnhancementsPluginStartDependencies } from '../types'; @@ -51,109 +44,15 @@ export class PPLSearchInterceptor extends SearchInterceptor { strategy?: string ): Observable { const { id, ...searchRequest } = request; - const dfContext: FetchDataFrameContext = { + const context: EnhancedFetchContext = { http: this.deps.http, path: trimEnd(API.PPL_SEARCH), signal, }; - const { timefilter } = this.queryService; - const dateRange = timefilter.timefilter.getTime(); - const { fromDate, toDate } = formatTimePickerDate(dateRange, 'YYYY-MM-DD HH:mm:ss.SSS'); - - const getTimeFilter = (timeField: any) => { - return ` | where \`${timeField}\` >= '${formatDate( - fromDate - )}' and \`${timeField}\` <= '${formatDate(toDate)}'`; - }; - - const insertTimeFilter = (query: string, filter: string) => { - return `${query}${filter}`; - }; - - const getAggQsFn = ({ - query, - aggConfig, - timeField, - timeFilter, - }: { - query: Query; - aggConfig: DataFrameAggConfig; - timeField: any; - timeFilter: string; - }) => { - return removeKeyword(`${query.query} ${getAggString(timeField, aggConfig)} ${timeFilter}`); - }; - - const getAggString = (timeField: any, aggsConfig?: DataFrameAggConfig) => { - if (!aggsConfig) { - return ` | stats count() by span(${timeField}, ${this.aggsService.calculateAutoTimeExpression( - { - from: fromDate, - to: toDate, - mode: 'absolute', - } - )})`; - } - if (aggsConfig.date_histogram) { - return ` | stats count() by span(${timeField}, ${ - aggsConfig.date_histogram.fixed_interval ?? - aggsConfig.date_histogram.calendar_interval ?? - this.aggsService.calculateAutoTimeExpression({ - from: fromDate, - to: toDate, - mode: 'absolute', - }) - })`; - } - if (aggsConfig.avg) { - return ` | stats avg(${aggsConfig.avg.field})`; - } - if (aggsConfig.cardinality) { - return ` | dedup ${aggsConfig.cardinality.field} | stats count()`; - } - if (aggsConfig.terms) { - return ` | stats count() by ${aggsConfig.terms.field}`; - } - if (aggsConfig.id === 'other-filter') { - const uniqueConfig = getUniqueValuesForRawAggs(aggsConfig); - if ( - !uniqueConfig || - !uniqueConfig.field || - !uniqueConfig.values || - uniqueConfig.values.length === 0 - ) { - return ''; - } - - let otherQueryString = ` | stats count() by ${uniqueConfig.field}`; - uniqueConfig.values.forEach((value, index) => { - otherQueryString += ` ${index === 0 ? '| where' : 'and'} ${ - uniqueConfig.field - }<>'${value}'`; - }); - return otherQueryString; - } - }; - const dataFrame = getRawDataFrame(searchRequest); - const query = this.queryService.queryString.getQuery(); - const timeField = query.dataset?.timeFieldName; - const aggConfig = dataFrame?.meta?.aggConfig; - if (timeField && aggConfig) { - const timeFilter = getTimeFilter(timeField); - const newQuery = insertTimeFilter(query.query as string, timeFilter); - updateDataFrameMeta({ - dataFrame, - query: { ...query, query: newQuery }, - aggConfig: dataFrame?.meta?.aggConfig, - timeField, - timeFilter, - getAggQsFn: getAggQsFn.bind(this), - }); - query.query += timeFilter; - } + const query = this.buildQuery(); - return fetchDataFrame(dfContext, query, dataFrame).pipe( + return fetch(context, query, this.getAggConfig(searchRequest, query)).pipe( catchError((error) => { return throwError(error); }) @@ -163,4 +62,57 @@ export class PPLSearchInterceptor extends SearchInterceptor { public search(request: IOpenSearchDashboardsSearchRequest, options: ISearchOptions) { return this.runSearch(request, options.abortSignal, SEARCH_STRATEGY.PPL); } + + private buildQuery() { + const query: Query = this.queryService.queryString.getQuery(); + const dataset = query.dataset; + if (!dataset || !dataset.timeFieldName) return query; + const timeFilter = this.getTimeFilter(dataset.timeFieldName); + return { ...query, query: query.query + timeFilter }; + } + + private getAggConfig(request: IOpenSearchDashboardsSearchRequest, query: Query) { + const { aggs } = request.params.body; + if (!aggs || !query.dataset || !query.dataset.timeFieldName) return; + const aggsConfig: QueryAggConfig = {}; + const { fromDate, toDate } = formatTimePickerDate( + this.queryService.timefilter.timefilter.getTime(), + 'YYYY-MM-DD HH:mm:ss.SSS' + ); + Object.entries(aggs as Record).forEach(([key, value]) => { + const aggTypeKeys = Object.keys(value); + if (aggTypeKeys.length === 0) { + return aggsConfig; + } + const aggTypeKey = aggTypeKeys[0]; + if (aggTypeKey === 'date_histogram') { + aggsConfig[aggTypeKey] = { + ...value[aggTypeKey], + }; + aggsConfig.qs = { + [key]: `${query.query} | stats count() by span(${query.dataset!.timeFieldName}, ${ + value[aggTypeKey].fixed_interval ?? + value[aggTypeKey].calendar_interval ?? + this.aggsService.calculateAutoTimeExpression({ + from: fromDate, + to: toDate, + mode: 'absolute', + }) + })`, + }; + } + }); + + return aggsConfig; + } + + private getTimeFilter(timeFieldName: string) { + const { fromDate, toDate } = formatTimePickerDate( + this.queryService.timefilter.timefilter.getTime(), + 'YYYY-MM-DD HH:mm:ss.SSS' + ); + return ` | where \`${timeFieldName}\` >= '${formatDate( + fromDate + )}' and \`${timeFieldName}\` <= '${formatDate(toDate)}'`; + } } diff --git a/src/plugins/query_enhancements/public/search/sql_search_interceptor.ts b/src/plugins/query_enhancements/public/search/sql_search_interceptor.ts index 3225367df105..69e4e14af562 100644 --- a/src/plugins/query_enhancements/public/search/sql_search_interceptor.ts +++ b/src/plugins/query_enhancements/public/search/sql_search_interceptor.ts @@ -5,9 +5,8 @@ import { trimEnd } from 'lodash'; import { Observable, throwError } from 'rxjs'; -import { i18n } from '@osd/i18n'; -import { concatMap, map } from 'rxjs/operators'; -import { DATA_FRAME_TYPES, getRawDataFrame } from '../../../data/common'; +import { catchError } from 'rxjs/operators'; +import { Query } from '../../../data/common'; import { DataPublicPluginStart, IOpenSearchDashboardsSearchRequest, @@ -15,29 +14,18 @@ import { ISearchOptions, SearchInterceptor, SearchInterceptorDeps, - getAsyncSessionId, - setAsyncSessionId, } from '../../../data/public'; -import { - API, - DataFramePolling, - FetchDataFrameContext, - SEARCH_STRATEGY, - fetchDataFrame, - fetchDataFramePolling, -} from '../../common'; +import { API, DATASET, EnhancedFetchContext, SEARCH_STRATEGY, fetch } from '../../common'; import { QueryEnhancementsPluginStartDependencies } from '../types'; export class SQLSearchInterceptor extends SearchInterceptor { protected queryService!: DataPublicPluginStart['query']; - protected aggsService!: DataPublicPluginStart['search']['aggs']; constructor(deps: SearchInterceptorDeps) { super(deps); deps.startServices.then(([coreStart, depsStart]) => { this.queryService = (depsStart as QueryEnhancementsPluginStartDependencies).data.query; - this.aggsService = (depsStart as QueryEnhancementsPluginStartDependencies).data.search.aggs; }); } @@ -47,110 +35,47 @@ export class SQLSearchInterceptor extends SearchInterceptor { strategy?: string ): Observable { const { id, ...searchRequest } = request; - const dfContext: FetchDataFrameContext = { + const context: EnhancedFetchContext = { http: this.deps.http, path: trimEnd(API.SQL_SEARCH), signal, }; - const dataFrame = getRawDataFrame(searchRequest); - - return fetchDataFrame(dfContext, this.queryService.queryString.getQuery(), dataFrame); - } - - protected runSearchAsync( - request: IOpenSearchDashboardsSearchRequest, - signal?: AbortSignal, - strategy?: string - ): Observable { - const { id, ...searchRequest } = request; - const path = trimEnd(API.SQL_ASYNC_SEARCH); - const dfContext: FetchDataFrameContext = { - http: this.deps.http, - path, - signal, - }; - - const dataFrame = getRawDataFrame(searchRequest); - const query = this.queryService.queryString.getQuery(); + const query = this.buildQuery(strategy); - const dataSourceRef = query.dataset - ? { - dataSourceId: query.dataset.dataSource?.id, - dataSourceName: query.dataset.dataSource?.title, - } - : {}; - - dataFrame.meta = { - ...dataFrame?.meta, - queryConfig: { - ...dataFrame?.meta.queryConfig, - ...dataSourceRef, - }, - sessionId: dataSourceRef ? getAsyncSessionId(dataSourceRef.dataSourceName!) : {}, - }; - - const onPollingSuccess = (pollingResult: any) => { - if (pollingResult && pollingResult.body.meta.status === 'SUCCESS') { - return false; - } - if (pollingResult && pollingResult.body.meta.status === 'FAILED') { - const jsError = new Error(pollingResult.data.error.response); - this.deps.toasts.addError(jsError, { - title: i18n.translate('queryEnhancements.sqlQueryError', { - defaultMessage: 'Could not complete the SQL async query', - }), - toastMessage: pollingResult.data.error.response, - }); - return false; - } - - this.deps.toasts.addInfo({ - title: i18n.translate('queryEnhancements.sqlQueryPolling', { - defaultMessage: `Polling query job results. Status: ${pollingResult.body.meta.status}`, - }), - }); - - return true; - }; - - const onPollingError = (error: Error) => { - throw new Error(error.message); - }; - - this.deps.toasts.addInfo({ - title: i18n.translate('queryEnhancements.sqlQueryInfo', { - defaultMessage: 'Starting query job...', - }), - }); - return fetchDataFrame(dfContext, query, dataFrame).pipe( - concatMap((jobResponse) => { - const df = jobResponse.body; - if (dataSourceRef?.dataSourceName && df?.meta?.sessionId) { - setAsyncSessionId(dataSourceRef.dataSourceName, df?.meta?.sessionId); - } - const dataFramePolling = new DataFramePolling( - () => fetchDataFramePolling(dfContext, df), - 5000, - onPollingSuccess, - onPollingError - ); - return dataFramePolling.fetch().pipe( - map(() => { - const dfPolling = dataFramePolling.data; - dfPolling.type = DATA_FRAME_TYPES.DEFAULT; - return dfPolling; - }) - ); + return fetch(context, query).pipe( + catchError((error) => { + return throwError(error); }) ); } public search(request: IOpenSearchDashboardsSearchRequest, options: ISearchOptions) { const dataset = this.queryService.queryString.getQuery().dataset; - if (dataset?.type === 'S3') { - return this.runSearchAsync(request, options.abortSignal, SEARCH_STRATEGY.SQL_ASYNC); - } - return this.runSearch(request, options.abortSignal, SEARCH_STRATEGY.SQL); + const strategy = dataset?.type === DATASET.S3 ? SEARCH_STRATEGY.SQL_ASYNC : SEARCH_STRATEGY.SQL; + return this.runSearch(request, options.abortSignal, strategy); + } + + private buildQuery(strategy?: string): Query { + const query: Query = this.queryService.queryString.getQuery(); + // TODO: MQL keeping here for S3 + // const dataset = query.dataset; + + // if (strategy === SEARCH_STRATEGY.SQL_ASYNC && dataset?.dataSource) { + // const sessionId = this.queryService.queryString + // .getLanguageService() + // .getUserQuerySessionId(dataset.dataSource.title); + // if (sessionId) { + // return { + // ...query, + // meta: { + // ...query.meta, + // sessionId, + // }, + // }; + // } + // } + + return query; } } diff --git a/src/plugins/query_enhancements/server/routes/index.ts b/src/plugins/query_enhancements/server/routes/index.ts index 33896c9236cd..687c943ee16b 100644 --- a/src/plugins/query_enhancements/server/routes/index.ts +++ b/src/plugins/query_enhancements/server/routes/index.ts @@ -16,6 +16,40 @@ import { API, SEARCH_STRATEGY } from '../../common'; import { registerQueryAssistRoutes } from './query_assist'; import { registerDataSourceConnectionsRoutes } from './data_source_connection'; +/** + * Defines a route for a specific search strategy. + * + * @experimental This function is experimental and might change in future releases. + * + * @param logger - The logger instance. + * @param router - The router instance. + * @param searchStrategies - The available search strategies. + * @param searchStrategyId - The ID of the search strategy to use. + * + * @example + * API Request Body: + * ```json + * { + * "query": { + * "query": "SELECT * FROM my_index", + * "language": "sql", + * "dataset": { + * "id": "my_dataset_id", + * "title": "My Dataset" + * }, + * "format": "json" + * }, + * @experimental + * "aggConfig": { + * // Optional aggregation configuration + * }, + * @deprecated + * "df": { + * // Optional data frame configuration + * } + * } + * ``` + */ function defineRoute( logger: Logger, router: IRouter, @@ -37,6 +71,7 @@ function defineRoute( dataset: schema.nullable(schema.object({}, { unknowns: 'allow' })), format: schema.string(), }), + aggConfig: schema.nullable(schema.object({}, { unknowns: 'allow' })), df: schema.nullable(schema.object({}, { unknowns: 'allow' })), }), }, @@ -125,6 +160,16 @@ function defineRoute( ); } +/** + * Defines routes for various search strategies and registers additional routes. + * + * @experimental This function is experimental and might change in future releases. + * + * @param logger - The logger instance. + * @param router - The router instance. + * @param client - The client instance. + * @param searchStrategies - The available search strategies. + */ export function defineRoutes( logger: Logger, router: IRouter, diff --git a/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts b/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts index 95fa1ef6f537..856bf056f748 100644 --- a/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts +++ b/src/plugins/query_enhancements/server/search/ppl_search_strategy.ts @@ -5,7 +5,7 @@ import { SharedGlobalConfig, Logger, ILegacyClusterClient } from 'opensearch-dashboards/server'; import { Observable } from 'rxjs'; -import { ISearchStrategy, getDefaultSearchParams, SearchUsage } from '../../../data/server'; +import { ISearchStrategy, SearchUsage } from '../../../data/server'; import { DATA_FRAME_TYPES, IDataFrameError, @@ -17,6 +17,7 @@ import { } from '../../../data/common'; import { getFields } from '../../common/utils'; import { Facet } from '../utils'; +import { QueryAggConfig } from '../../common'; export const pplSearchStrategyProvider = ( config$: Observable, @@ -32,43 +33,11 @@ export const pplSearchStrategyProvider = ( shimResponse: true, }); - const parseRequest = (query: string) => { - const pipeMap = new Map(); - const pipeArray = query.split('|'); - pipeArray.forEach((pipe, index) => { - const splitChar = index === 0 ? '=' : ' '; - const split = pipe.trim().split(splitChar); - const key = split[0]; - const value = pipe.replace(index === 0 ? `${key}=` : key, '').trim(); - pipeMap.set(key, value); - }); - - const source = pipeMap.get('source'); - - const filters = pipeMap.get('where'); - - const stats = pipeMap.get('stats'); - const aggsQuery = stats - ? `source=${source} ${filters ? `| where ${filters}` : ''} | stats ${stats}` - : undefined; - - return { - aggs: aggsQuery, - }; - }; - return { search: async (context, request: any, options) => { - const uiSettingsClient = await context.core.uiSettings.client; - - const { dataFrameHydrationStrategy, ...defaultParams } = await getDefaultSearchParams( - uiSettingsClient - ); - try { const query: Query = request.body.query; - const { df } = request.body; - + const aggConfig: QueryAggConfig | undefined = request.body.aggConfig; const rawResponse: any = await pplFacet.describeQuery(context, request); if (!rawResponse.success) { @@ -82,7 +51,7 @@ export const pplSearchStrategyProvider = ( const dataFrame = createDataFrame({ name: query.dataset?.id, schema: rawResponse.data.schema, - meta: df?.meta, + meta: aggConfig, fields: getFields(rawResponse), }); @@ -90,10 +59,9 @@ export const pplSearchStrategyProvider = ( if (usage) usage.trackSuccess(rawResponse.took); - if (dataFrame?.meta?.aggsQs) { - for (const [key, aggQueryString] of Object.entries(dataFrame?.meta?.aggsQs)) { - const aggRequest = parseRequest(aggQueryString as string); - request.body.query = aggRequest.aggs; + if (aggConfig) { + for (const [key, aggQueryString] of Object.entries(aggConfig.qs)) { + request.body.query.query = aggQueryString; const rawAggs: any = await pplFacet.describeQuery(context, request); (dataFrame as IDataFrameWithAggs).aggs = {}; (dataFrame as IDataFrameWithAggs).aggs[key] = rawAggs.data.datarows?.map((hit: any) => { diff --git a/src/plugins/query_enhancements/server/search/sql_search_strategy.test.ts b/src/plugins/query_enhancements/server/search/sql_search_strategy.test.ts index 9742ec04b969..822534879040 100644 --- a/src/plugins/query_enhancements/server/search/sql_search_strategy.test.ts +++ b/src/plugins/query_enhancements/server/search/sql_search_strategy.test.ts @@ -17,8 +17,14 @@ import { IDataFrameError, IDataFrameResponse, IOpenSearchDashboardsSearchRequest, + Query, } from '../../../data/common'; import * as facet from '../utils/facet'; +import * as utils from '../../common/utils'; + +jest.mock('../../common/utils', () => ({ + getFields: jest.fn(), +})); describe('sqlSearchStrategyProvider', () => { let config$: Observable; @@ -64,12 +70,16 @@ describe('sqlSearchStrategyProvider', () => { describeQuery: jest.fn().mockResolvedValue(mockResponse), } as unknown) as facet.Facet; jest.spyOn(facet, 'Facet').mockImplementation(() => mockFacet); + (utils.getFields as jest.Mock).mockReturnValue([ + { name: 'field1', type: 'long' }, + { name: 'field2', type: 'text' }, + ]); const strategy = sqlSearchStrategyProvider(config$, logger, client, usage); const result = await strategy.search( emptyRequestHandlerContext, ({ - body: { query: { qs: 'SELECT * FROM table' }, df: { name: 'table' } }, + body: { query: { query: 'SELECT * FROM table', dataset: { id: 'test-dataset' } } }, } as unknown) as IOpenSearchDashboardsSearchRequest, {} ); @@ -77,15 +87,19 @@ describe('sqlSearchStrategyProvider', () => { expect(result).toEqual({ type: DATA_FRAME_TYPES.DEFAULT, body: { - name: 'table', + name: 'test-dataset', fields: [ - { name: 'field1', type: 'long', values: [1, 2] }, - { name: 'field2', type: 'text', values: ['value1', 'value2'] }, + { name: 'field1', type: 'long', values: [] }, + { name: 'field2', type: 'text', values: [] }, + ], + schema: [ + { name: 'field1', type: 'long', values: [] }, + { name: 'field2', type: 'text', values: [] }, ], size: 2, }, took: 100, - } as IDataFrameResponse); + }); expect(usage.trackSuccess).toHaveBeenCalledWith(100); }); @@ -104,16 +118,16 @@ describe('sqlSearchStrategyProvider', () => { const result = await strategy.search( emptyRequestHandlerContext, ({ - body: { query: { qs: 'SELECT * FROM table' } }, + body: { query: { query: 'SELECT * FROM table' } }, } as unknown) as IOpenSearchDashboardsSearchRequest, {} ); - expect(result).toEqual(({ + expect(result).toEqual({ type: DATA_FRAME_TYPES.ERROR, body: { error: { cause: 'Query failed' } }, took: 50, - } as unknown) as IDataFrameError); + } as IDataFrameError); }); it('should handle exceptions', async () => { @@ -128,7 +142,7 @@ describe('sqlSearchStrategyProvider', () => { strategy.search( emptyRequestHandlerContext, ({ - body: { query: { qs: 'SELECT * FROM table' } }, + body: { query: { query: 'SELECT * FROM table' } }, } as unknown) as IOpenSearchDashboardsSearchRequest, {} ) @@ -136,4 +150,53 @@ describe('sqlSearchStrategyProvider', () => { expect(logger.error).toHaveBeenCalledWith(`sqlSearchStrategy: ${mockError.message}`); expect(usage.trackError).toHaveBeenCalled(); }); + + it('should handle empty search response', async () => { + const mockResponse = { + success: true, + data: { + schema: [ + { name: 'field1', type: 'long' }, + { name: 'field2', type: 'text' }, + ], + datarows: [], + }, + took: 10, + }; + const mockFacet = ({ + describeQuery: jest.fn().mockResolvedValue(mockResponse), + } as unknown) as facet.Facet; + jest.spyOn(facet, 'Facet').mockImplementation(() => mockFacet); + (utils.getFields as jest.Mock).mockReturnValue([ + { name: 'field1', type: 'long' }, + { name: 'field2', type: 'text' }, + ]); + + const strategy = sqlSearchStrategyProvider(config$, logger, client, usage); + const result = await strategy.search( + emptyRequestHandlerContext, + ({ + body: { query: { query: 'SELECT * FROM empty_table', dataset: { id: 'empty-dataset' } } }, + } as unknown) as IOpenSearchDashboardsSearchRequest, + {} + ); + + expect(result).toEqual({ + type: DATA_FRAME_TYPES.DEFAULT, + body: { + name: 'empty-dataset', + fields: [ + { name: 'field1', type: 'long', values: [] }, + { name: 'field2', type: 'text', values: [] }, + ], + schema: [ + { name: 'field1', type: 'long', values: [] }, + { name: 'field2', type: 'text', values: [] }, + ], + size: 0, + }, + took: 10, + }); + expect(usage.trackSuccess).toHaveBeenCalledWith(10); + }); }); diff --git a/src/plugins/query_enhancements/server/search/sql_search_strategy.ts b/src/plugins/query_enhancements/server/search/sql_search_strategy.ts index f95a032b3f1e..ffc7f0a6f0cd 100644 --- a/src/plugins/query_enhancements/server/search/sql_search_strategy.ts +++ b/src/plugins/query_enhancements/server/search/sql_search_strategy.ts @@ -11,22 +11,30 @@ import { IDataFrameError, IDataFrameResponse, IOpenSearchDashboardsSearchRequest, - PartialDataFrame, + Query, createDataFrame, } from '../../../data/common'; +import { getFields } from '../../common/utils'; import { Facet } from '../utils'; export const sqlSearchStrategyProvider = ( - _config$: Observable, + config$: Observable, logger: Logger, client: ILegacyClusterClient, usage?: SearchUsage ): ISearchStrategy => { - const sqlFacet = new Facet({ client, logger, endpoint: 'ppl.sqlQuery' }); + const sqlFacet = new Facet({ + client, + logger, + endpoint: 'enhancements.sqlQuery', + useJobs: false, + shimResponse: true, + }); return { - search: async (context, request: any, _options) => { + search: async (context, request: any, options) => { try { + const query: Query = request.body.query; const rawResponse: any = await sqlFacet.describeQuery(context, request); if (!rawResponse.success) { @@ -37,16 +45,13 @@ export const sqlSearchStrategyProvider = ( } as IDataFrameError; } - const partial: PartialDataFrame = { - ...request.body.df, - fields: rawResponse.data?.schema || [], - }; - const dataFrame = createDataFrame(partial); - dataFrame.fields?.forEach((field, index) => { - field.values = rawResponse.data.datarows.map((row: any) => row[index]); + const dataFrame = createDataFrame({ + name: query.dataset?.id, + schema: rawResponse.data.schema, + fields: getFields(rawResponse), }); - dataFrame.size = rawResponse.data.datarows?.length || 0; + dataFrame.size = rawResponse.data.datarows.length; if (usage) usage.trackSuccess(rawResponse.took); From 8ed61c9c39aeac289dcabd20f8271c5df3b41fd7 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:28:53 -0700 Subject: [PATCH 265/276] [Discover 2.0] Fixed recent query and Data Selector styles (#7918) (#7927) (cherry picked from commit 7f9aabbb02a7fe96f86b007663fe2774ceb6ad98) Signed-off-by: Ashwin P Chandran Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../config/global_selectors.json | 3 +- .../language_service/_recent_query.scss | 9 +- .../language_service/recent_query.tsx | 220 +++++++----------- .../query/query_string/query_history.ts | 76 +++--- .../_dataset_configurator.scss | 2 +- .../dataset_selector/_dataset_explorer.scss | 3 +- .../dataset_selector/_dataset_selector.scss | 6 + .../public/ui/query_editor/query_editor.tsx | 42 ++-- 8 files changed, 181 insertions(+), 180 deletions(-) diff --git a/packages/osd-stylelint-config/config/global_selectors.json b/packages/osd-stylelint-config/config/global_selectors.json index ca442760f731..0427337a298b 100644 --- a/packages/osd-stylelint-config/config/global_selectors.json +++ b/packages/osd-stylelint-config/config/global_selectors.json @@ -27,7 +27,8 @@ "src/plugins/discover/public/application/view_components/canvas/discover_canvas.scss", "src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss", "src/plugins/data/public/ui/query_string_input/_query_bar.scss", - "src/plugins/data/public/ui/query_editor/_query_editor.scss" + "src/plugins/data/public/ui/query_editor/_query_editor.scss", + "src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss" ] } } \ No newline at end of file diff --git a/src/plugins/data/public/query/query_string/language_service/_recent_query.scss b/src/plugins/data/public/query/query_string/language_service/_recent_query.scss index faac658f685f..4b7a30ce85af 100644 --- a/src/plugins/data/public/query/query_string/language_service/_recent_query.scss +++ b/src/plugins/data/public/query/query_string/language_service/_recent_query.scss @@ -1,4 +1,9 @@ .recentQuery__table { - padding: $euiSizeXS; - width: 1320px; + border: $euiBorderThin; + border-radius: $euiSizeXS; + margin: 0 $euiSizeXS $euiSizeXS; + + thead { + background-color: $euiColorLightestShade; + } } diff --git a/src/plugins/data/public/query/query_string/language_service/recent_query.tsx b/src/plugins/data/public/query/query_string/language_service/recent_query.tsx index d058cb5c692a..0db291af8d31 100644 --- a/src/plugins/data/public/query/query_string/language_service/recent_query.tsx +++ b/src/plugins/data/public/query/query_string/language_service/recent_query.tsx @@ -5,165 +5,115 @@ import './_recent_query.scss'; -import { - EuiBasicTable, - EuiButtonEmpty, - EuiButtonIcon, - EuiCopy, - EuiPopover, - EuiText, -} from '@elastic/eui'; +import React, { useEffect, useState } from 'react'; +import { EuiBasicTable, EuiBasicTableColumn, EuiButtonIcon, EuiCopy } from '@elastic/eui'; import moment from 'moment'; - -import React, { useCallback, useEffect, useState } from 'react'; import { Query, TimeRange } from 'src/plugins/data/common'; import { QueryStringContract } from '../query_string_manager'; -// TODO: Need to confirm this number -export const MAX_RECENT_QUERY_SIZE = 10; - interface RecentQueryItem { query: Query; time: number; timeRange?: TimeRange; } -export function RecentQuery(props: { +interface RecentQueryTableItem { + id: number; + query: Query['query']; + time: string; +} + +interface RecentQueriesTableProps { queryString: QueryStringContract; - query: Query; onClickRecentQuery: (query: Query, timeRange?: TimeRange) => void; -}) { - const [recentQueries, setRecentQueries] = useState( - props.queryString.getQueryHistory() - ); - const [isPopoverOpen, setPopover] = useState(false); - const onButtonClick = () => { - setPopover(!isPopoverOpen); - }; + isVisible: boolean; +} - const clearHistory = useCallback(() => { - props.queryString?.clearQueryHistory(); - setRecentQueries(props.queryString?.getQueryHistory()); - }, [props.queryString]); +export const MAX_RECENT_QUERY_SIZE = 10; - const clear = () => { - clearHistory(); - }; +export function RecentQueriesTable({ + queryString, + onClickRecentQuery, + isVisible, +}: RecentQueriesTableProps) { + const currentLanguage = queryString.getQuery().language; + const [recentQueries, setRecentQueries] = useState( + queryString.getQueryHistory() + ); useEffect(() => { - const done = props.queryString.changeQueryHistory(setRecentQueries); + const done = queryString.changeQueryHistory(setRecentQueries); return () => done(); - }, [props.queryString]); - - const getRowProps = (item: any) => { - const { id } = item; - return { - 'data-test-subj': `row-${id}`, - className: 'customRowClass', - onClick: () => {}, - }; - }; - - const getCellProps = (item: any, column: any) => { - const { id } = item; - const { field } = column; - return { - className: 'customCellClass', - 'data-test-subj': `cell-${id}-${field}`, - textOnly: true, - }; - }; - - const actions = [ - { - name: 'Run', - description: 'Run recent query', - icon: 'play', - type: 'icon', - onClick: (item) => { - props.onClickRecentQuery(recentQueries[item.id].query, recentQueries[item.id].timeRange); - setPopover(false); - }, - 'data-test-subj': 'action-run', - }, - { - render: (item) => { - return ( - - {(copy) => ( - - )} - - ); - }, - }, - ]; - - const tableColumns = [ + }, [queryString]); + + const getRowProps = (item: any) => ({ + 'data-test-subj': `row-${item.id}`, + className: 'customRowClass', + onClick: () => {}, + }); + + const getCellProps = (item: any, column: any) => ({ + className: 'customCellClass', + 'data-test-subj': `cell-${item.id}-${column.field}`, + textOnly: true, + }); + + const tableColumns: Array> = [ + { field: 'query', name: 'Recent query' }, + { field: 'time', name: 'Last run', width: '200px' }, { - field: 'query', - name: 'Recent query', + name: 'Actions', + actions: [ + { + name: 'Run', + description: 'Run recent query', + icon: 'play', + type: 'icon', + onClick: (item: RecentQueryTableItem) => { + onClickRecentQuery(recentQueries[item.id].query, recentQueries[item.id].timeRange); + }, + 'data-test-subj': 'action-run', + }, + { + render: (item: RecentQueryTableItem) => ( + + {(copy) => ( + + )} + + ), + }, + ], + width: '70px', }, - { - field: 'language', - name: 'Language', - }, - { - field: 'time', - name: 'Last run', - }, - { name: 'Actions', actions }, ]; - const recentQueryItems = recentQueries + const recentQueryItems: RecentQueryTableItem[] = recentQueries .filter((item, idx) => idx < MAX_RECENT_QUERY_SIZE) - .map((query, idx) => { - const date = moment(query.time); - - const formattedDate = date.format('MMM D, YYYY HH:mm:ss'); - - let queryLanguage = query.query.language; - if (queryLanguage === 'kuery') { - queryLanguage = 'DQL'; - } - - const tableItem = { - id: idx, - query: query.query.query, - timeRange: query.timeRange, - language: queryLanguage, - time: formattedDate, - }; + .filter((item) => item.query.language === currentLanguage) + .map((query, idx) => ({ + id: idx, + query: query.query.query, + timeRange: query.timeRange, + time: moment(query.time).format('MMM D, YYYY HH:mm:ss'), + })); - return tableItem; - }); + if (!isVisible) return null; return ( - - - {'Recent queries'} - - - } - isOpen={isPopoverOpen} - closePopover={() => setPopover(false)} - panelPaddingSize="none" - anchorPosition={'downRight'} - > - - + ); } diff --git a/src/plugins/data/public/query/query_string/query_history.ts b/src/plugins/data/public/query/query_string/query_history.ts index 04e2285add1c..277287ee09d8 100644 --- a/src/plugins/data/public/query/query_string/query_history.ts +++ b/src/plugins/data/public/query/query_string/query_history.ts @@ -4,60 +4,82 @@ */ import { BehaviorSubject } from 'rxjs'; -import { DataStorage, Dataset } from '../../../common'; +import { DataStorage } from '../../../common'; import { Query, TimeRange } from '../..'; -// Todo: Implement a more advanced QueryHistory class when needed for recent query history +const MAX_HISTORY_SIZE = 500; +export const HISTORY_KEY_PREFIX = 'query_'; + export class QueryHistory { - constructor(private readonly storage: DataStorage) {} + private changeEmitter: BehaviorSubject; - private changeEmitter = new BehaviorSubject(this.getHistory() || []); + constructor(private readonly storage: DataStorage) { + this.changeEmitter = new BehaviorSubject(this.getHistory()); + } - getHistoryKeys() { + public getHistoryKeys(): string[] { return this.storage .keys() - .filter((key: string) => key.indexOf('query_') === 0) - .sort() - .reverse(); + .filter((key: string) => key.startsWith(HISTORY_KEY_PREFIX)) + .sort((a, b) => { + const timeA = parseInt(a.split('_')[1], 10); + const timeB = parseInt(b.split('_')[1], 10); + return timeB - timeA; // Sort in descending order (most recent first) + }); } - getHistory() { - return this.getHistoryKeys().map((key) => this.storage.get(key)); + public getHistory(): any[] { + return this.getHistoryKeys() + .map((key) => this.storage.get(key)) + .sort((a, b) => b.time - a.time); } - // This is used as an optimization mechanism so that different components - // can listen for changes to history and update because changes to history can - // be triggered from different places in the app. The alternative would be to store - // this in state so that we hook into the React model, but it would require loading history - // every time the application starts even if a user is not going to view history. - change(listener: (reqs: any[]) => void) { + public change(listener: (reqs: any[]) => void): () => void { const subscription = this.changeEmitter.subscribe(listener); return () => subscription.unsubscribe(); } - addQueryToHistory(query: Query, dateRange?: TimeRange) { - const keys = this.getHistoryKeys(); - keys.splice(0, 500); // only maintain most recent X; - keys.forEach((key) => { - this.storage.remove(key); + public addQueryToHistory(query: Query, dateRange?: TimeRange): void { + const existingKeys = this.getHistoryKeys(); + + // Check if the query already exists + const existingKey = existingKeys.find((key) => { + const item = this.storage.get(key); + return item && item.query.query === query.query && item.query.language === query.language; }); - const timestamp = new Date().getTime(); - const k = 'query_' + timestamp; - this.storage.set(k, { + if (existingKey) { + // If the query exists, remove it from its current position + this.storage.remove(existingKey); + existingKeys.splice(existingKeys.indexOf(existingKey), 1); + } + + // Add the new query to the front + const timestamp = Date.now(); + const newKey = `${HISTORY_KEY_PREFIX}${timestamp}`; + const newItem = { time: timestamp, query, dateRange, - }); + }; + this.storage.set(newKey, newItem); + + // Trim the history if it exceeds the maximum size + if (existingKeys.length >= MAX_HISTORY_SIZE) { + const keysToRemove = existingKeys.slice(MAX_HISTORY_SIZE - 1); + keysToRemove.forEach((key) => this.storage.remove(key)); + } + // Emit the updated history this.changeEmitter.next(this.getHistory()); } - clearHistory() { + public clearHistory(): void { this.getHistoryKeys().forEach((key) => this.storage.remove(key)); + this.changeEmitter.next([]); } } -export function createHistory(deps: { storage: DataStorage }) { +export function createHistory(deps: { storage: DataStorage }): QueryHistory { return new QueryHistory(deps.storage); } diff --git a/src/plugins/data/public/ui/dataset_selector/_dataset_configurator.scss b/src/plugins/data/public/ui/dataset_selector/_dataset_configurator.scss index 44e89b19ffb3..5f70c956c2f2 100644 --- a/src/plugins/data/public/ui/dataset_selector/_dataset_configurator.scss +++ b/src/plugins/data/public/ui/dataset_selector/_dataset_configurator.scss @@ -1,3 +1,3 @@ .datasetConfigurator { - height: 600px; + height: 100%; } diff --git a/src/plugins/data/public/ui/dataset_selector/_dataset_explorer.scss b/src/plugins/data/public/ui/dataset_selector/_dataset_explorer.scss index 0011db04fa29..704a49f010a6 100644 --- a/src/plugins/data/public/ui/dataset_selector/_dataset_explorer.scss +++ b/src/plugins/data/public/ui/dataset_selector/_dataset_explorer.scss @@ -1,7 +1,8 @@ .datasetExplorer { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 240px)) minmax(300px, 1fr); - height: 600px; + height: 100%; + max-height: calc(100vh - 200px); overflow-x: auto; border: $euiBorderThin; diff --git a/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss b/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss index ea780f1c22e8..0fd82fc1b9ca 100644 --- a/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss +++ b/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss @@ -18,6 +18,12 @@ &__advancedModal { width: 1200px; + height: 800px; + max-height: calc(100vh - $euiSizeS); + + .euiModal__flex { + max-height: none; + } } &__checkbox { diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index 3c9e81b4824d..2ff643f74254 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -6,6 +6,7 @@ import { i18n } from '@osd/i18n'; import { + EuiButtonEmpty, EuiButtonIcon, EuiCompressedFieldText, EuiFlexGroup, @@ -27,7 +28,7 @@ import { QueryEditorExtensions } from './query_editor_extensions'; import { getQueryService, getIndexPatterns } from '../../services'; import { DatasetSelector } from '../dataset_selector'; import { QueryControls } from '../../query/query_string/language_service/get_query_control_links'; -import { RecentQuery } from '../../query/query_string/language_service/recent_query'; +import { RecentQueriesTable } from '../../query/query_string/language_service/recent_query'; import { DefaultInputProps } from './editors'; const LANGUAGE_ID_SQL = 'SQL'; @@ -73,6 +74,7 @@ interface State { isCollapsed: boolean; timeStamp: IFieldType | null; lineCount: number | undefined; + isRecentQueryVisible: boolean; } // Needed for React.lazy @@ -87,6 +89,7 @@ export default class QueryEditorUI extends Component { isCollapsed: false, // default to expand mode timeStamp: null, lineCount: undefined, + isRecentQueryVisible: false, }; public inputRef: monaco.editor.IStandaloneCodeEditor | null = null; @@ -184,12 +187,6 @@ export default class QueryEditorUI extends Component { this.setState({ lineCount: currentLineCount }); }; - private onClickInput = (event: React.MouseEvent) => { - if (event.target instanceof HTMLTextAreaElement) { - this.onQueryStringChange(event.target.value); - } - }; - // TODO: MQL consider moving language select language of setting search source here private onSelectLanguage = (languageId: string) => { // Send telemetry info every time the user opts in or out of kuery @@ -216,6 +213,13 @@ export default class QueryEditorUI extends Component { this.setState({ index }); }; + private toggleRecentQueries = () => { + this.setState((prevState) => ({ + ...prevState, + isRecentQueryVisible: !prevState.isRecentQueryVisible, + })); + }; + public componentDidMount() { const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { @@ -358,11 +362,16 @@ export default class QueryEditorUI extends Component { , ], end: [ - , + + + {'Recent queries'} + + , ], }, provideCompletionItems: this.provideCompletionItems, @@ -441,7 +450,14 @@ export default class QueryEditorUI extends Component { className={classNames('osdQueryEditor__header', this.props.headerClassName)} /> {!this.state.isCollapsed && ( -
{languageEditor.Body()}
+ <> +
{languageEditor.Body()}
+ + )} {this.renderQueryEditorExtensions()} From e99e98d327dff948962c4e413e1143be37a40f03 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:29:02 -0700 Subject: [PATCH 266/276] [discover] S3 data connection (#7917) (#7928) Update the S3 type config. This commit does: Browsing connections, databases, tables Creating a dataset from a table and setting the string correctly. This commit does NOT: Cache data structures Use session ID for querying Re-add async polling to search interceptor --------- (cherry picked from commit 1f4cbbb30964ae8fc63137ca443c2b122def9681) Signed-off-by: Kawika Avilla Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7917.yml | 2 + src/plugins/data/common/constants.ts | 7 +- .../dataset_service/dataset_service.ts | 7 +- .../dataset_service/lib/index_pattern_type.ts | 4 +- .../dataset_service/lib/index_type.ts | 20 +- .../query_string/dataset_service/types.ts | 6 +- .../ui/dataset_selector/advanced_selector.tsx | 8 +- .../ui/dataset_selector/dataset_explorer.tsx | 8 +- .../ui/dataset_selector/dataset_selector.tsx | 8 +- .../public/datasets/s3_handler.ts | 246 ++++++++++++++---- 10 files changed, 226 insertions(+), 90 deletions(-) create mode 100644 changelogs/fragments/7917.yml diff --git a/changelogs/fragments/7917.yml b/changelogs/fragments/7917.yml new file mode 100644 index 000000000000..60262ad04c44 --- /dev/null +++ b/changelogs/fragments/7917.yml @@ -0,0 +1,2 @@ +feat: +- Add S3 data exploration for connections, databases, and tables ([#7917](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7917)) \ No newline at end of file diff --git a/src/plugins/data/common/constants.ts b/src/plugins/data/common/constants.ts index 97c465762986..289d56d4d064 100644 --- a/src/plugins/data/common/constants.ts +++ b/src/plugins/data/common/constants.ts @@ -38,10 +38,15 @@ export const DEFAULT_DATA = { type: 'ROOT', meta: { type: DATA_STRUCTURE_META_TYPES.FEATURE, - icon: 'folderOpen', + icon: { type: 'folderOpen' }, tooltip: 'Root Data Structure', }, } as DataStructure, + LOCAL_DATASOURCE: { + id: '', + title: 'Local Cluster', + type: 'DATA_SOURCE', + }, }, SET_TYPES: { diff --git a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts index ee4ab700e847..faa35328075f 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { CoreStart, SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { CoreStart } from 'opensearch-dashboards/public'; import { Dataset, DataStructure, @@ -15,6 +15,7 @@ import { import { DatasetTypeConfig } from './types'; import { indexPatternTypeConfig, indexTypeConfig } from './lib'; import { IndexPatternsContract } from '../../../index_patterns'; +import { IDataPluginServices } from '../../../types'; export class DatasetService { private indexPatterns?: IndexPatternsContract; @@ -83,7 +84,7 @@ export class DatasetService { } public fetchOptions( - savedObjects: SavedObjectsClientContract, + services: IDataPluginServices, path: DataStructure[], dataType: string ): Promise { @@ -91,7 +92,7 @@ export class DatasetService { if (!type) { throw new Error(`No handler found for type: ${path[0]}`); } - return type.fetch(savedObjects, path); + return type.fetch(services, path); } private async fetchDefaultDataset(): Promise { diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts index 1034850c41ba..b92fb70631f6 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts @@ -44,9 +44,9 @@ export const indexPatternTypeConfig: DatasetTypeConfig = { } as Dataset; }, - fetch: async (savedObjects, path) => { + fetch: async (services, path) => { const dataStructure = path[path.length - 1]; - const indexPatterns = await fetchIndexPatterns(savedObjects); + const indexPatterns = await fetchIndexPatterns(services.savedObjects.client); return { ...dataStructure, columnHeader: 'Index patterns', diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts index fe18afbd2e76..73df7b1af556 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts @@ -15,14 +15,6 @@ import { DatasetTypeConfig } from '../types'; import { getSearchService, getIndexPatterns } from '../../../../services'; import { injectMetaToDataStructures } from './utils'; -const INDEX_INFO = { - LOCAL_DATASOURCE: { - id: '', - title: 'Local Cluster', - type: 'DATA_SOURCE', - }, -}; - export const indexTypeConfig: DatasetTypeConfig = { id: DEFAULT_DATA.SET_TYPES.INDEX, title: 'Indexes', @@ -47,11 +39,11 @@ export const indexTypeConfig: DatasetTypeConfig = { title: dataSource.title, type: dataSource.type, } - : INDEX_INFO.LOCAL_DATASOURCE, + : DEFAULT_DATA.STRUCTURES.LOCAL_DATASOURCE, }; }, - fetch: async (savedObjects, path) => { + fetch: async (services, path) => { const dataStructure = path[path.length - 1]; switch (dataStructure.type) { case 'DATA_SOURCE': { @@ -69,7 +61,7 @@ export const indexTypeConfig: DatasetTypeConfig = { } default: { - const dataSources = await fetchDataSources(savedObjects); + const dataSources = await fetchDataSources(services.savedObjects.client); return { ...dataStructure, columnHeader: 'Cluster', @@ -97,12 +89,12 @@ export const indexTypeConfig: DatasetTypeConfig = { }; const fetchDataSources = async (client: SavedObjectsClientContract) => { - const resp = await client.find({ + const response = await client.find({ type: 'data-source', perPage: 10000, }); - const dataSources: DataStructure[] = [INDEX_INFO.LOCAL_DATASOURCE].concat( - resp.savedObjects.map((savedObject) => ({ + const dataSources: DataStructure[] = [DEFAULT_DATA.STRUCTURES.LOCAL_DATASOURCE].concat( + response.savedObjects.map((savedObject) => ({ id: savedObject.id, title: savedObject.attributes.title, type: 'DATA_SOURCE', diff --git a/src/plugins/data/public/query/query_string/dataset_service/types.ts b/src/plugins/data/public/query/query_string/dataset_service/types.ts index 8d597694ac49..0ea84d67f2a0 100644 --- a/src/plugins/data/public/query/query_string/dataset_service/types.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/types.ts @@ -2,9 +2,9 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ -import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; import { EuiIconProps } from '@elastic/eui'; import { Dataset, DatasetField, DataStructure } from '../../../../common'; +import { IDataPluginServices } from '../../../types'; /** * Configuration for handling dataset operations. @@ -29,11 +29,11 @@ export interface DatasetTypeConfig { toDataset: (path: DataStructure[]) => Dataset; /** * Fetches child options for a given DataStructure. - * @param {SavedObjectsClientContract} client - The saved objects client. + * @param {IDataPluginServices} services - The data plugin services. * @param {DataStructure} dataStructure - The parent DataStructure. * @returns {Promise} A promise that resolves to a DatasetHandlerFetchResponse. */ - fetch: (client: SavedObjectsClientContract, path: DataStructure[]) => Promise; + fetch: (services: IDataPluginServices, path: DataStructure[]) => Promise; /** * Fetches fields for the dataset. * @returns {Promise} A promise that resolves to an array of DatasetFields. diff --git a/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx b/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx index 8afaedbb492e..734153452eea 100644 --- a/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx +++ b/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx @@ -4,7 +4,6 @@ */ import React, { useState } from 'react'; -import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; import { BaseDataset, DATA_STRUCTURE_META_TYPES, @@ -15,13 +14,14 @@ import { import { DatasetExplorer } from './dataset_explorer'; import { Configurator } from './configurator'; import { getQueryService } from '../../services'; +import { IDataPluginServices } from '../../types'; export const AdvancedSelector = ({ - savedObjects, + services, onSelect, onCancel, }: { - savedObjects: SavedObjectsClientContract; + services: IDataPluginServices; onSelect: (dataset: Dataset) => void; onCancel: () => void; }) => { @@ -59,7 +59,7 @@ export const AdvancedSelector = ({ /> ) : ( void; @@ -55,7 +55,7 @@ export const DatasetExplorer = ({ } setLoading(true); - const nextDataStructure = await typeConfig.fetch(savedObjects, nextPath); + const nextDataStructure = await typeConfig.fetch(services, nextPath); setLoading(false); setPath([...newPath, nextDataStructure]); diff --git a/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx b/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx index 0a251a8dfe3e..d442360e4d59 100644 --- a/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx +++ b/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx @@ -34,7 +34,7 @@ export const DatasetSelector = ({ }: DatasetSelectorProps) => { const [isOpen, setIsOpen] = useState(false); const [datasets, setDatasets] = useState([]); - const { overlays, savedObjects } = services; + const { overlays } = services; const isMounted = useRef(true); @@ -53,7 +53,7 @@ export const DatasetSelector = ({ const typeConfig = datasetService.getType(DEFAULT_DATA.SET_TYPES.INDEX_PATTERN); if (!typeConfig) return; - const fetchedIndexPatternDataStructures = await typeConfig.fetch(savedObjects.client, []); + const fetchedIndexPatternDataStructures = await typeConfig.fetch(services, []); if (!isMounted.current) return; @@ -67,7 +67,7 @@ export const DatasetSelector = ({ if (!selectedDataset && fetchedDatasets.length > 0) { setSelectedDataset(fetchedDatasets[0]); } - }, [datasetService, savedObjects.client, selectedDataset, setSelectedDataset]); + }, [datasetService, selectedDataset, services, setSelectedDataset]); useEffect(() => { fetchDatasets(); @@ -183,7 +183,7 @@ export const DatasetSelector = ({ const overlay = overlays?.openModal( toMountPoint( { overlay?.close(); if (dataset) { diff --git a/src/plugins/query_enhancements/public/datasets/s3_handler.ts b/src/plugins/query_enhancements/public/datasets/s3_handler.ts index 2613f016143f..f54435df293f 100644 --- a/src/plugins/query_enhancements/public/datasets/s3_handler.ts +++ b/src/plugins/query_enhancements/public/datasets/s3_handler.ts @@ -3,111 +3,247 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; -import { DataStructure, Dataset, DatasetField } from 'src/plugins/data/common'; -import { DatasetTypeConfig } from 'src/plugins/data/public'; +import { HttpSetup, SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { timer } from 'rxjs'; +import { filter, map, mergeMap, takeWhile } from 'rxjs/operators'; +import { + DATA_STRUCTURE_META_TYPES, + DEFAULT_DATA, + DataSourceMeta, + DataStructure, + DataStructureCustomMeta, + Dataset, + DatasetField, +} from '../../../data/common'; +import { DatasetTypeConfig, IDataPluginServices } from '../../../data/public'; import { DATASET } from '../../common'; const S3_ICON = 'visTable'; export const s3TypeConfig: DatasetTypeConfig = { id: DATASET.S3, - title: DATASET.S3, + title: 'S3 Connections', meta: { icon: { type: S3_ICON }, - tooltip: 'S3 Data Source', + tooltip: 'Amazon S3 Connections', }, toDataset: (path: DataStructure[]): Dataset => { - const s3 = path[path.length - 1]; - const dataSource = path.find((ds) => ds.type === DATASET.S3); + const dataSource = path.find((ds) => ds.type === 'DATA_SOURCE'); + const connection = path.find((ds) => ds.type === 'CONNECTION'); + const database = path.find((ds) => ds.type === 'DATABASE'); + const table = path[path.length - 1]; return { - id: s3.id, - title: s3.title, + id: table.id, + title: `${connection?.title}.${database?.title}.${table.title}`, type: DATASET.S3, dataSource: dataSource ? { id: dataSource.id, title: dataSource.title, type: dataSource.type, + meta: table.meta as DataSourceMeta, } - : undefined, + : DEFAULT_DATA.STRUCTURES.LOCAL_DATASOURCE, }; }, - fetch: async ( - savedObjects: SavedObjectsClientContract, - path: DataStructure[] - ): Promise => { + fetch: async (services: IDataPluginServices, path: DataStructure[]): Promise => { const dataStructure = path[path.length - 1]; + const { + http, + savedObjects: { client }, + } = services; + switch (dataStructure.type) { - case DATASET.S3: + case 'DATA_SOURCE': { + const connections = await fetchConnections(http, dataStructure); return { ...dataStructure, - columnHeader: 'Connections', hasNext: true, - children: [ - { - id: `${dataStructure.id}::mys3`, - title: 'mys3', - type: 'CONNECTION', - }, - ], + columnHeader: 'Connections', + children: connections, }; - case 'CONNECTION': + } + case 'CONNECTION': { + const databases = await fetchDatabases(http, path); return { ...dataStructure, columnHeader: 'Databases', hasNext: true, - children: [ - { - id: `${dataStructure.id}.defaultDb`, - title: 'defaultDb', - type: 'DATABASE', - }, - ], + children: databases, }; - case 'DATABASE': + } + case 'DATABASE': { + const tables = await fetchTables(http, path); return { ...dataStructure, columnHeader: 'Tables', hasNext: false, - children: [ - { - id: `${dataStructure.id}.table1`, - title: 'table1', - type: 'TABLE', - }, - { - id: `${dataStructure.id}.table2`, - title: 'table2', - type: 'TABLE', - }, - ], + children: tables, }; - default: - const s3DataSources = await fetchS3DataSources(savedObjects); + } + default: { + const dataSources = await fetchDataSources(client); return { ...dataStructure, - columnHeader: 'S3 Data Sources', - hasNext: false, - children: s3DataSources, + columnHeader: 'Clusters', + hasNext: true, + children: dataSources, }; + } } }, fetchFields: async (dataset: Dataset): Promise => { - // This is a placeholder. You'll need to implement the actual logic to fetch S3 fields. - // For now, we'll return an empty array. return []; }, - supportedLanguages: (): string[] => { - return ['sql']; // Assuming S3 only supports SQL queries + supportedLanguages: (dataset: Dataset): string[] => { + return ['SQL']; }, }; -const fetchS3DataSources = async (client: SavedObjectsClientContract): Promise => { - return []; +const fetch = ( + http: HttpSetup, + path: DataStructure[], + type: 'DATABASE' | 'TABLE' +): Promise => { + return new Promise((resolve, reject) => { + const dataSource = path.find((ds) => ds.type === 'DATA_SOURCE'); + const parent = path[path.length - 1]; + const meta = parent.meta as DataStructureCustomMeta; + + timer(0, 5000) + .pipe( + mergeMap(() => + http.fetch('../../api/enhancements/datasource/jobs', { + query: { + id: dataSource?.id, + queryId: meta.query.id, + }, + }) + ), + takeWhile( + (response) => response.status !== 'SUCCESS' && response.status !== 'FAILED', + true + ), + filter((response) => response.status === 'SUCCESS'), + map((response) => { + if (response.status === 'FAILED') { + throw new Error('Job failed'); + } + return response.datarows.map((item: string[]) => ({ + id: `${parent.id}.${item[type === 'DATABASE' ? 0 : 1]}`, + title: item[type === 'DATABASE' ? 0 : 1], + type, + meta: { + type: DATA_STRUCTURE_META_TYPES.CUSTOM, + query: meta.query, + session: meta.session, + } as DataStructureCustomMeta, + })); + }) + ) + .subscribe({ + next: (dataStructures) => { + resolve(dataStructures); + }, + error: (error) => { + reject(error); + }, + complete: () => { + reject(new Error('No response')); + }, + }); + }); +}; + +const setMeta = (dataStructure: DataStructure, response: any) => { + return { + ...dataStructure.meta, + query: { id: response.queryId }, + session: { id: response.sessionId }, + } as DataStructureCustomMeta; +}; + +const fetchDataSources = async (client: SavedObjectsClientContract): Promise => { + const resp = await client.find({ + type: 'data-source', + perPage: 10000, + }); + const dataSources: DataStructure[] = [DEFAULT_DATA.STRUCTURES.LOCAL_DATASOURCE]; + return dataSources.concat( + resp.savedObjects.map((savedObject) => ({ + id: savedObject.id, + title: savedObject.attributes.title, + type: 'DATA_SOURCE', + meta: { + query: { + id: savedObject.id, + }, + type: DATA_STRUCTURE_META_TYPES.CUSTOM, + } as DataStructureCustomMeta, + })) + ); +}; + +const fetchConnections = async ( + http: HttpSetup, + dataSource: DataStructure +): Promise => { + const query = (dataSource.meta as DataStructureCustomMeta).query; + const response = await http.fetch(`../../api/enhancements/datasource/external`, { + query, + }); + + return response + .filter((ds: any) => ds.connector === 'S3GLUE') + .map((ds: any) => ({ + id: `${dataSource.id}::${ds.name}`, + title: ds.name, + type: 'CONNECTION', + meta: { + query, + type: DATA_STRUCTURE_META_TYPES.CUSTOM, + } as DataStructureCustomMeta, + })); +}; + +const fetchDatabases = async (http: HttpSetup, path: DataStructure[]): Promise => { + const dataSource = path.find((ds) => ds.type === 'DATA_SOURCE'); + const connection = path[path.length - 1]; + const query = (connection.meta as DataStructureCustomMeta).query; + const response = await http.post(`../../api/enhancements/datasource/jobs`, { + body: JSON.stringify({ + lang: 'sql', + query: `SHOW DATABASES in ${connection.title}`, + datasource: dataSource?.title, + }), + query, + }); + + connection.meta = setMeta(connection, response); + + return fetch(http, path, 'DATABASE'); +}; + +const fetchTables = async (http: HttpSetup, path: DataStructure[]): Promise => { + const dataSource = path.find((ds) => ds.type === 'DATA_SOURCE'); + const database = path[path.length - 1]; + const response = await http.post(`../../api/enhancements/datasource/jobs`, { + body: JSON.stringify({ + lang: 'sql', + query: `SHOW TABLES in ${database.title}`, + datasource: dataSource?.title, + }), + query: { + id: dataSource?.id, + }, + }); + + database.meta = setMeta(database, response); + + return fetch(http, path, 'TABLE'); }; From 9cea0c11d9b976c46740212c4167997253435ab1 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:44:30 +0800 Subject: [PATCH 267/276] [Workspace]Add right sidebar to workspace create form (#7750) (#7931) * Move workspace form inside workspace creator * Remove enter details panel * Rename workspace_form to workspace_creator_form * Clarify workspace form types * Add right sidebar to workspace creator * Add submitting lock for workspace create page * Changeset file for PR #7750 created/updated * Fix form submitting lock not been covered --------- (cherry picked from commit 76d7a8bbf7af1ec220e4b67f71e482bbc804a8d6) Signed-off-by: Lin Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7750.yml | 2 + .../workspace_faq_panel.test.tsx.snap | 66 +++++ .../components/workspace_creator/utils.ts | 19 ++ .../workspace_create_action_panel.test.tsx | 16 ++ .../workspace_create_action_panel.tsx | 25 +- .../workspace_creator.test.tsx | 25 ++ .../workspace_creator/workspace_creator.tsx | 20 +- .../workspace_creator_form.scss | 31 +++ .../workspace_creator_form.test.tsx} | 11 +- .../workspace_creator_form.tsx | 236 ++++++++++++++++++ .../workspace_faq_panel.test.tsx | 15 ++ .../workspace_creator/workspace_faq_panel.tsx | 72 ++++++ .../workspace_form_summary_panel.test.tsx | 182 ++++++++++++++ .../workspace_form_summary_panel.tsx | 193 ++++++++++++++ .../components/workspace_form/fields/index.ts | 7 + .../public/components/workspace_form/index.ts | 24 +- .../public/components/workspace_form/types.ts | 27 +- .../workspace_form/use_workspace_form.test.ts | 4 +- .../workspace_form/use_workspace_form.ts | 11 +- .../public/components/workspace_form/utils.ts | 16 +- .../workspace_form/workspace_detail_form.tsx | 7 +- .../workspace_enter_details_panel.tsx | 72 ------ .../workspace_form/workspace_form.tsx | 152 ----------- .../workspace_form/workspace_use_case.tsx | 1 - 24 files changed, 952 insertions(+), 282 deletions(-) create mode 100644 changelogs/fragments/7750.yml create mode 100644 src/plugins/workspace/public/components/workspace_creator/__snapshots__/workspace_faq_panel.test.tsx.snap create mode 100644 src/plugins/workspace/public/components/workspace_creator/utils.ts rename src/plugins/workspace/public/components/{workspace_form => workspace_creator}/workspace_create_action_panel.test.tsx (80%) rename src/plugins/workspace/public/components/{workspace_form => workspace_creator}/workspace_create_action_panel.tsx (71%) create mode 100644 src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.scss rename src/plugins/workspace/public/components/{workspace_form/workspace_form.test.tsx => workspace_creator/workspace_creator_form.test.tsx} (89%) create mode 100644 src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.tsx create mode 100644 src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.test.tsx create mode 100644 src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.tsx create mode 100644 src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.test.tsx create mode 100644 src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.tsx create mode 100644 src/plugins/workspace/public/components/workspace_form/fields/index.ts delete mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx delete mode 100644 src/plugins/workspace/public/components/workspace_form/workspace_form.tsx diff --git a/changelogs/fragments/7750.yml b/changelogs/fragments/7750.yml new file mode 100644 index 000000000000..a9ec74c2cdc9 --- /dev/null +++ b/changelogs/fragments/7750.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace]Add right sidebar to workspace create form ([#7750](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7750)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_creator/__snapshots__/workspace_faq_panel.test.tsx.snap b/src/plugins/workspace/public/components/workspace_creator/__snapshots__/workspace_faq_panel.test.tsx.snap new file mode 100644 index 000000000000..9fe60a2ab6e1 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/__snapshots__/workspace_faq_panel.test.tsx.snap @@ -0,0 +1,66 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`WorkspaceFaqPanel renders correctly 1`] = ` +
+
+
+

+ FAQs +

+
+
+

+ Can I change the workspace use case later? +

+

+ You can only change to the All use case after workspace creation. +

+
+
+
+
+

+ Why can’t I find the data sources I want to attached to the workspace? +

+

+ Available data sources to all workspaces here are configured by OpenSearch admin. Contact OpenSearch admin within your organization to add the requested data source. +

+
+
+
+
+

+ Do the added team members automatically gain access to the attached data sources? +

+

+ No. Adding team members will only grant them access to the created workspace. To grant access to the attached data sources, contact the data source admin within your organization. +

+
+
+
+
+
+`; diff --git a/src/plugins/workspace/public/components/workspace_creator/utils.ts b/src/plugins/workspace/public/components/workspace_creator/utils.ts new file mode 100644 index 000000000000..9be647c1a30b --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/utils.ts @@ -0,0 +1,19 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const RIGHT_SIDEBAR_SCROLL_KEY = 'data-right-sidebar-scroll'; + +export enum RightSidebarScrollField { + Name = 'name', + Description = 'description', + Color = 'color', + UseCase = 'useCase', + DataSource = 'dataSource', + Member = 'member', +} + +export const generateRightSidebarScrollProps = (key: RightSidebarScrollField) => { + return { [RIGHT_SIDEBAR_SCROLL_KEY]: key }; +}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx similarity index 80% rename from src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.test.tsx rename to src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx index 6f1dbc58bf9e..3fd6e78ac7d1 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.test.tsx @@ -27,6 +27,7 @@ describe('WorkspaceCreateActionPanel', () => { formId={formId} formData={{ name: longName, description: formData.description }} application={mockApplication} + isSubmitting={false} /> ); const createButton = screen.getByText('Create workspace'); @@ -40,6 +41,7 @@ describe('WorkspaceCreateActionPanel', () => { formId={formId} formData={{ name: formData.name, description: longDescription }} application={mockApplication} + isSubmitting={false} /> ); const createButton = screen.getByText('Create workspace'); @@ -52,9 +54,23 @@ describe('WorkspaceCreateActionPanel', () => { formId={formId} formData={formData} application={mockApplication} + isSubmitting={false} /> ); const createButton = screen.getByText('Create workspace'); expect(createButton.closest('button')).not.toBeDisabled(); }); + + it('should disable the "Create Workspace" and "Cancel" button when submitting', () => { + render( + + ); + expect(screen.getByText('Create workspace').closest('button')).toBeDisabled(); + expect(screen.getByText('Cancel').closest('button')).toBeDisabled(); + }); }); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx similarity index 71% rename from src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.tsx rename to src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx index 0b914c0a7658..5f59cbb9587b 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_create_action_panel.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_create_action_panel.tsx @@ -3,12 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiSmallButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiSmallButton, EuiFlexGroup, EuiFlexItem, EuiSmallButtonEmpty } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import React, { useState, useCallback } from 'react'; import type { ApplicationStart } from 'opensearch-dashboards/public'; -import type { WorkspaceFormData } from './types'; -import { WorkspaceCancelModal } from './workspace_cancel_modal'; +import { WorkspaceFormDataState, WorkspaceCancelModal } from '../workspace_form'; import { MAX_WORKSPACE_DESCRIPTION_LENGTH, MAX_WORKSPACE_NAME_LENGTH, @@ -16,14 +15,16 @@ import { interface WorkspaceCreateActionPanelProps { formId: string; - formData: Partial>; + formData: Pick; application: ApplicationStart; + isSubmitting: boolean; } export const WorkspaceCreateActionPanel = ({ formId, formData, application, + isSubmitting, }: WorkspaceCreateActionPanelProps) => { const [isCancelModalVisible, setIsCancelModalVisible] = useState(false); const closeCancelModal = useCallback(() => setIsCancelModalVisible(false), []); @@ -34,26 +35,28 @@ export const WorkspaceCreateActionPanel = ({ return ( <> - + - - {i18n.translate('workspace.form.bottomBar.cancel', { + {i18n.translate('workspace.form.right.sidebar.buttons.cancelText', { defaultMessage: 'Cancel', })} - + - {i18n.translate('workspace.form.bottomBar.createWorkspace', { + {i18n.translate('workspace.form.right.sidebar.buttons.createWorkspaceText', { defaultMessage: 'Create workspace', })} diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx index 760c4060de58..9200ea7cfa07 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.test.tsx @@ -344,4 +344,29 @@ describe('WorkspaceCreator', () => { }); expect(notificationToastsAddDanger).not.toHaveBeenCalled(); }); + + it('should not create workspace API when submitting', async () => { + workspaceClientCreate.mockImplementationOnce( + () => + new Promise((resolve) => { + setTimeout(resolve, 100); + }) + ); + const { getByTestId } = render(); + // Ensure workspace create form rendered + await waitFor(() => { + expect(getByTestId('workspaceForm-bottomBar-createButton')).toBeInTheDocument(); + }); + fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); + expect(workspaceClientCreate).toHaveBeenCalledTimes(1); + + // Since create button was been disabled, fire form submit event by form directly + fireEvent.submit(getByTestId('workspaceCreatorForm')); + expect(workspaceClientCreate).toHaveBeenCalledTimes(1); + + await waitFor(() => { + fireEvent.click(getByTestId('workspaceForm-bottomBar-createButton')); + expect(workspaceClientCreate).toHaveBeenCalledTimes(2); + }); + }); }); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx index a7a2b247914a..3ba8b7850753 100644 --- a/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator.tsx @@ -3,13 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useCallback } from 'react'; +import React, { useCallback, useState } from 'react'; import { EuiPage, EuiPageBody, EuiPageContent, euiPaletteColorBlind } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { BehaviorSubject } from 'rxjs'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; -import { WorkspaceForm, WorkspaceFormSubmitData, WorkspaceOperationType } from '../workspace_form'; +import { WorkspaceFormSubmitData, WorkspaceOperationType } from '../workspace_form'; import { WORKSPACE_DETAIL_APP_ID } from '../../../common/constants'; import { formatUrlWithWorkspaceId } from '../../../../../core/public/utils'; import { WorkspaceClient } from '../../workspace_client'; @@ -17,10 +17,10 @@ import { convertPermissionSettingsToPermissions } from '../workspace_form'; import { DataSource } from '../../../common/types'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; import { WorkspaceUseCase } from '../../types'; -import { WorkspaceFormData } from '../workspace_form/types'; import { getUseCaseFeatureConfig } from '../../utils'; import { useFormAvailableUseCases } from '../workspace_form/use_form_available_use_cases'; import { NavigationPublicPluginStart } from '../../../../../plugins/navigation/public'; +import { WorkspaceCreatorForm } from './workspace_creator_form'; export interface WorkspaceCreatorProps { registeredUseCases$: BehaviorSubject; @@ -43,6 +43,7 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { dataSourceManagement?: DataSourceManagementPluginSetup; navigationUI: NavigationPublicPluginStart['ui']; }>(); + const [isFormSubmitting, setIsFormSubmitting] = useState(false); const isPermissionEnabled = application?.capabilities.workspaces.permissionEnabled; const { isOnlyAllowEssential, availableUseCases } = useFormAvailableUseCases({ @@ -52,7 +53,7 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { }); const defaultSelectedUseCase = availableUseCases?.[0]; - const defaultWorkspaceFormValues: Partial = { + const defaultWorkspaceFormValues: Partial = { color: euiPaletteColorBlind()[0], ...(defaultSelectedUseCase ? { @@ -65,6 +66,10 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { const handleWorkspaceFormSubmit = useCallback( async (data: WorkspaceFormSubmitData) => { let result; + if (isFormSubmitting) { + return; + } + setIsFormSubmitting(true); try { const { permissionSettings, selectedDataSources, ...attributes } = data; const selectedDataSourceIds = (selectedDataSources ?? []).map((ds: DataSource) => { @@ -105,9 +110,11 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { text: error instanceof Error ? error.message : JSON.stringify(error), }); return; + } finally { + setIsFormSubmitting(false); } }, - [notifications?.toasts, http, application, workspaceClient] + [notifications?.toasts, http, application, workspaceClient, isFormSubmitting] ); const isFormReadyToRender = @@ -137,7 +144,7 @@ export const WorkspaceCreator = (props: WorkspaceCreatorProps) => { hasShadow={false} > {isFormReadyToRender && ( - { dataSourceManagement={dataSourceManagement} availableUseCases={availableUseCases} defaultValues={defaultWorkspaceFormValues} + isSubmitting={isFormSubmitting} /> )} diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.scss b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.scss new file mode 100644 index 000000000000..010406b8797a --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.scss @@ -0,0 +1,31 @@ +$workspaceCreateRightSideBarTopOffset: 116px; +$workspaceCreateRightSideBarBottomOffset: 100px; + +.workspaceCreateRightSidebar { + position: sticky; + top: $workspaceCreateRightSideBarTopOffset; + max-height: calc(100vh - $workspaceCreateRightSideBarTopOffset - $workspaceCreateRightSideBarBottomOffset); + overflow: hidden; + display: flex; + flex-direction: column; + width: 280px; + + @include ouiBreakpoint("xs","s") { + position: static; + width: 100%; + } +} + +.workspaceCreateRightSideBarContentWrapper { + overflow-y: scroll; + + @include ouiBreakpoint("xs","s") { + overflow: visible; + } +} + +.workspaceCreateRightSideBarActionsWrapper { + padding: $ouiSizeM; + border-radius: $ouiSizeM; + background: $ouiColorEmptyShade; +} diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.test.tsx similarity index 89% rename from src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx rename to src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.test.tsx index 66279a68a1b6..95ca5bf948c5 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.test.tsx +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.test.tsx @@ -8,8 +8,8 @@ import { fireEvent, render } from '@testing-library/react'; import { coreMock } from '../../../../../core/public/mocks'; import { DataSourceManagementPluginSetup } from '../../../../../plugins/data_source_management/public'; import { createMockedRegisteredUseCases } from '../../mocks'; -import { WorkspaceOperationType } from './constants'; -import { WorkspaceForm } from './workspace_form'; +import { WorkspaceOperationType } from '../workspace_form'; +import { WorkspaceCreatorForm } from './workspace_creator_form'; const mockCoreStart = coreMock.createStart(); @@ -37,7 +37,8 @@ const setup = ( }; return render( - { it('should enable data source panel for dashboard admin and when data source is enabled', () => { const { getByText } = setup(true, mockDataSourceManagementSetup); - expect(getByText('Associate data source')).toBeInTheDocument(); + expect(getByText('Associate data sources')).toBeInTheDocument(); }); it('should not display data source panel for non dashboard admin', () => { const { queryByText } = setup(false, mockDataSourceManagementSetup); - expect(queryByText('Associate data source')).not.toBeInTheDocument(); + expect(queryByText('Associate data sources')).not.toBeInTheDocument(); }); it('should not display data source panel when data source is disabled', () => { diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.tsx new file mode 100644 index 000000000000..9ab0a35e722b --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_creator_form.tsx @@ -0,0 +1,236 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useCallback, useRef } from 'react'; +import { + EuiSpacer, + EuiTitle, + EuiForm, + EuiText, + EuiCompressedFormRow, + EuiColorPicker, + EuiFlexItem, + EuiFlexGroup, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { + useWorkspaceForm, + WorkspacePermissionSettingPanel, + WorkspaceUseCase, + WorkspaceFormErrorCallout, + SelectDataSourcePanel, + usersAndPermissionsCreatePageTitle, + WorkspaceFormProps, + WorkspaceNameField, + WorkspaceDescriptionField, +} from '../workspace_form'; + +import { WorkspaceCreateActionPanel } from './workspace_create_action_panel'; +import { WorkspaceFaqPanel } from './workspace_faq_panel'; +import { WorkspaceFormSummaryPanel } from './workspace_form_summary_panel'; +import { generateRightSidebarScrollProps, RightSidebarScrollField } from './utils'; + +import './workspace_creator_form.scss'; + +interface WorkspaceCreatorFormProps extends WorkspaceFormProps { + isSubmitting: boolean; +} + +export const WorkspaceCreatorForm = (props: WorkspaceCreatorFormProps) => { + const { + application, + savedObjects, + defaultValues, + permissionEnabled, + dataSourceManagement: isDataSourceEnabled, + availableUseCases, + } = props; + const { + formId, + formData, + formErrors, + numberOfErrors, + setName, + setDescription, + handleFormSubmit, + handleColorChange, + handleUseCaseChange: handleUseCaseChangeInHook, + setPermissionSettings, + setSelectedDataSources, + } = useWorkspaceForm(props); + const nameManualChangedRef = useRef(false); + + const disabledUserOrGroupInputIdsRef = useRef( + defaultValues?.permissionSettings?.map((item) => item.id) ?? [] + ); + const isDashboardAdmin = application?.capabilities?.dashboards?.isDashboardAdmin ?? false; + const handleNameInputChange = useCallback( + (newName) => { + setName(newName); + nameManualChangedRef.current = true; + }, + [setName] + ); + const handleUseCaseChange = useCallback( + (newUseCase) => { + handleUseCaseChangeInHook(newUseCase); + const useCase = availableUseCases.find((item) => newUseCase === item.id); + if (!nameManualChangedRef.current && useCase) { + setName(useCase.title); + } + }, + [handleUseCaseChangeInHook, availableUseCases, setName] + ); + + return ( + + + + {numberOfErrors > 0 && ( + <> + + + + )} + +

+ {i18n.translate('workspace.creator.form.customizeTitle', { + defaultMessage: 'Customize the workspace', + })} +

+
+
+ +
+ +
+ + +
+ + + +
+ + {i18n.translate('workspace.form.workspaceDetails.color.description', { + defaultMessage: + 'Select a background color for the icon representing this workspace.', + })} + + + +
+
+ + {/* SelectDataSourcePanel is only visible for dashboard admin and when data source is enabled*/} + {isDashboardAdmin && isDataSourceEnabled && ( + <> + +

+ {i18n.translate('workspace.creator.form.associateDataSourceTitle', { + defaultMessage: 'Associate data sources', + })} +

+
+ + {i18n.translate('workspace.creator.form.associateDataSourceDescription', { + defaultMessage: + 'Add data sources that will be available in the workspace. If a selected OpenSearch connection has embedded Direct Query connection, they will also be available in the workspace.', + })} + + + + + + )} + {permissionEnabled && ( + <> + +

{usersAndPermissionsCreatePageTitle}

+
+ + {i18n.translate('workspace.creator.form.usersAndPermissionsDescription', { + defaultMessage: + 'You will be added as an owner to the workspace. Select additional users and user groups as workspace collaborators with different access levels.', + })} + + + + + )} + + + +
+
+ + + +
+ +
+ +
+
+
+ + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.test.tsx new file mode 100644 index 000000000000..e8d737b32242 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.test.tsx @@ -0,0 +1,15 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { WorkspaceFaqPanel } from './workspace_faq_panel'; + +describe('WorkspaceFaqPanel', () => { + it('renders correctly', () => { + const tree = render(); + expect(tree.container).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.tsx new file mode 100644 index 000000000000..218e9a7618cf --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_faq_panel.tsx @@ -0,0 +1,72 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiCard, EuiSpacer, EuiText } from '@elastic/eui'; +import { i18n } from '@osd/i18n'; + +const WorkspaceFaqItem = ({ question, answer }: { question: string; answer: string }) => { + return ( + +

{question}

+

{answer}

+
+ ); +}; + +const FAQs = [ + { + question: i18n.translate('workspace.form.faq.panel.question1', { + defaultMessage: 'Can I change the workspace use case later?', + }), + answer: i18n.translate('workspace.form.faq.panel.answer1', { + defaultMessage: 'You can only change to the All use case after workspace creation.', + }), + }, + { + question: i18n.translate('workspace.form.faq.panel.question2', { + defaultMessage: 'Why can’t I find the data sources I want to attached to the workspace? ', + }), + answer: i18n.translate('workspace.form.faq.panel.answer2', { + defaultMessage: + 'Available data sources to all workspaces here are configured by OpenSearch admin. Contact OpenSearch admin within your organization to add the requested data source. ', + }), + }, + { + question: i18n.translate('workspace.form.faq.panel.question3', { + defaultMessage: + 'Do the added team members automatically gain access to the attached data sources?', + }), + answer: i18n.translate('workspace.form.faq.panel.answer3', { + defaultMessage: + 'No. Adding team members will only grant them access to the created workspace. To grant access to the attached data sources, contact the data source admin within your organization.', + }), + }, +]; + +export const WorkspaceFaqPanel = () => { + return ( + + {FAQs.map(({ question, answer }, index) => ( + + + {index !== FAQs.length - 1 && ( + <> + + + + )} + + ))} + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.test.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.test.tsx new file mode 100644 index 000000000000..4db2d9365ab9 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.test.tsx @@ -0,0 +1,182 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { + WorkspaceFormSummaryPanel, + ExpandableTextList, + FieldSummaryItem, +} from './workspace_form_summary_panel'; +import { RightSidebarScrollField } from './utils'; +import { WorkspacePermissionItemType } from '../workspace_form'; + +describe('WorkspaceFormSummaryPanel', () => { + const formData = { + features: [], + useCase: 'useCase1', + name: 'Test Workspace', + description: 'This is a test workspace', + color: '#000000', + selectedDataSources: [ + { id: 'data-source-1', title: 'Data Source 1' }, + { id: 'data-source-2', title: 'Data Source 2' }, + { id: 'data-source-3', title: 'Data Source 3' }, + ], + permissionSettings: [ + { id: 1, type: WorkspacePermissionItemType.User, userId: 'user1' }, + { id: 2, type: WorkspacePermissionItemType.Group, group: 'group1' }, + { id: 3, type: WorkspacePermissionItemType.User, userId: 'user2' }, + ], + }; + + const availableUseCases = [ + { + id: 'useCase1', + title: 'Use Case 1', + description: 'This is Use Case 1', + features: [], + }, + { + id: 'useCase2', + title: 'Use Case 2', + description: 'This is Use Case 2', + features: [], + }, + ]; + + it('renders summary panel with correct data', () => { + render( + + ); + + expect(screen.getByText('Summary')).toBeInTheDocument(); + expect(screen.getByText('Use Case 1')).toBeInTheDocument(); + expect(screen.getByText('This is Use Case 1')).toBeInTheDocument(); + expect(screen.getByText('Test Workspace')).toBeInTheDocument(); + expect(screen.getByText('This is a test workspace')).toBeInTheDocument(); + expect(screen.getByText('#000000')).toBeInTheDocument(); + expect(screen.getByText('Data Source 1')).toBeInTheDocument(); + expect(screen.getByText('user1')).toBeInTheDocument(); + expect(screen.getByText('group1')).toBeInTheDocument(); + expect(screen.queryByText('user2')).toBeNull(); + }); + + it('renders placeholders for empty form data', () => { + render( + + ); + + expect(screen.getByText('Summary')).toBeInTheDocument(); + + // Use case placeholder + const useCasePlaceholder = screen.getByTestId('workspaceFormRightSideBarSummary-useCase-Value'); + expect(useCasePlaceholder).toHaveTextContent('—'); + + // Name placeholder + const namePlaceholder = screen.getByTestId('workspaceFormRightSideBarSummary-name-Value'); + expect(namePlaceholder).toHaveTextContent('—'); + + // Description placeholder + const descriptionPlaceholder = screen.getByTestId( + 'workspaceFormRightSideBarSummary-description-Value' + ); + expect(descriptionPlaceholder).toHaveTextContent('—'); + + // Color placeholder + const colorPlaceholder = screen.getByTestId('workspaceFormRightSideBarSummary-color-Value'); + expect(colorPlaceholder).toHaveTextContent('—'); + + // Data sources placeholder + const dataSourcesPlaceholder = screen.getByTestId( + 'workspaceFormRightSideBarSummary-dataSource-Value' + ); + expect(dataSourcesPlaceholder).toHaveTextContent('—'); + + // Permissions placeholder + const permissionsPlaceholder = screen.getByTestId( + 'workspaceFormRightSideBarSummary-member-Value' + ); + expect(permissionsPlaceholder).toHaveTextContent('—'); + }); +}); + +describe('ExpandableTextList', () => { + it('renders all texts when expanded', () => { + const texts = ['Text 1', 'Text 2', 'Text 3', 'Text 4']; + render(); + + expect(screen.getByText('Text 1')).toBeInTheDocument(); + expect(screen.getByText('Text 2')).toBeInTheDocument(); + expect(screen.queryByText('Text 3')).not.toBeInTheDocument(); + expect(screen.queryByText('Text 4')).not.toBeInTheDocument(); + + fireEvent.click(screen.getByText('Show all')); + + expect(screen.getByText('Text 3')).toBeInTheDocument(); + expect(screen.getByText('Text 4')).toBeInTheDocument(); + }); + it('should not show "Show all" button when all texts can be displayed', () => { + const texts = ['Text 1', 'Text 2']; + render(); + + expect(screen.getByText('Text 1')).toBeInTheDocument(); + expect(screen.getByText('Text 2')).toBeInTheDocument(); + expect(screen.queryByText('Show all')).not.toBeInTheDocument(); + }); +}); + +describe('FieldSummaryItem', () => { + it('renders title and content correctly', () => { + render( + Content for Name + ); + + expect(screen.getByText('Name')).toBeInTheDocument(); + expect(screen.getByText('Content for Name')).toBeInTheDocument(); + }); + + it('renders placeholder when no content is provided', () => { + render(); + + expect(screen.getByText('Name')).toBeInTheDocument(); + expect(screen.getByText('—')).toBeInTheDocument(); + }); + + it('scrolls to the corresponding field when title is clicked', () => { + const originScrollIntoView = window.HTMLElement.prototype.scrollIntoView; + const scrollIntoViewMock = jest.fn(); + window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock; + + render( +
+
+ Content for Name +
+ ); + + fireEvent.click(screen.getByText('Name')); + + expect(scrollIntoViewMock).toHaveBeenCalledWith({ + behavior: 'smooth', + block: 'center', + }); + window.HTMLElement.prototype.scrollIntoView = originScrollIntoView; + }); +}); diff --git a/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.tsx b/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.tsx new file mode 100644 index 000000000000..a16cad76ede7 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_creator/workspace_form_summary_panel.tsx @@ -0,0 +1,193 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useCallback, useState } from 'react'; +import { + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiSpacer, + EuiText, + EuiTextColor, + EuiLink, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { WorkspaceFormDataState } from '../forms'; +import { WorkspaceUseCase } from '../../types'; +import { RightSidebarScrollField, RIGHT_SIDEBAR_SCROLL_KEY } from './utils'; + +const SCROLL_FIELDS = { + [RightSidebarScrollField.UseCase]: i18n.translate('workspace.form.summary.panel.useCase.title', { + defaultMessage: 'Use case', + }), + [RightSidebarScrollField.Name]: i18n.translate('workspace.form.summary.panel.name.title', { + defaultMessage: 'Name', + }), + [RightSidebarScrollField.Description]: i18n.translate( + 'workspace.form.summary.panel.description.title', + { + defaultMessage: 'Description', + } + ), + [RightSidebarScrollField.Color]: i18n.translate('workspace.form.summary.panel.color.title', { + defaultMessage: 'Accent color', + }), + [RightSidebarScrollField.DataSource]: i18n.translate( + 'workspace.form.summary.panel.dataSources.title', + { + defaultMessage: 'Data sources', + } + ), + [RightSidebarScrollField.Member]: i18n.translate('workspace.form.summary.panel.members.title', { + defaultMessage: 'Members', + }), +}; + +export const FieldSummaryItem = ({ + field, + children, + bottomGap = true, +}: React.PropsWithChildren<{ + field: RightSidebarScrollField; + bottomGap?: boolean; +}>) => { + const handleTitleClick = useCallback(() => { + const element = document.querySelector( + `.workspaceCreateFormContainer [${RIGHT_SIDEBAR_SCROLL_KEY}="${field}"]` + ); + + element?.scrollIntoView({ behavior: 'smooth', block: 'center' }); + }, [field]); + + return ( + <> + +
+ + {SCROLL_FIELDS[field]} + +
+
+ + + {!!children ? children : } + + {bottomGap && ( + <> + + + + )} + + ); +}; + +export const ExpandableTextList = ({ + texts, + collapseDisplayCount, +}: { + texts: string[]; + collapseDisplayCount: number; +}) => { + const [isExpanded, setIsExpanded] = useState(false); + const uniqueTexts = Array.from(new Set(texts)); + const displayedTexts = isExpanded ? uniqueTexts : uniqueTexts.slice(0, collapseDisplayCount); + return ( + <> + {displayedTexts.map((text) => ( + + {text} + + ))} + {uniqueTexts.length > collapseDisplayCount && ( + { + setIsExpanded((flag) => !flag); + }} + > + {isExpanded + ? i18n.translate('workspace.form.summary.members.showLess', { + defaultMessage: 'Show less', + }) + : i18n.translate('workspace.form.summary.members.showAll', { + defaultMessage: 'Show all', + })} + + )} + + ); +}; + +interface WorkspaceFormSummaryPanelProps { + formData: WorkspaceFormDataState; + availableUseCases: WorkspaceUseCase[]; + permissionEnabled?: boolean; +} + +export const WorkspaceFormSummaryPanel = ({ + formData, + availableUseCases, + permissionEnabled, +}: WorkspaceFormSummaryPanelProps) => { + const useCase = availableUseCases.find((item) => item.id === formData.useCase); + const userAndGroups = formData.permissionSettings.flatMap((setting) => { + if ('userId' in setting && !!setting.userId) { + return [setting.userId]; + } + if ('group' in setting && !!setting.group) { + return [setting.group]; + } + return []; + }); + + return ( + + + {useCase && ( + <> + {useCase.title} + {useCase.description} + + )} + + {formData.name} + + {formData.description?.trim()} + + + {formData.color && ( + + + + + + {formData.color} + + + )} + + + {formData.selectedDataSources.length > 0 && ( + title)} + collapseDisplayCount={2} + /> + )} + + {permissionEnabled && ( + + {userAndGroups.length > 0 && ( + + )} + + )} + + ); +}; diff --git a/src/plugins/workspace/public/components/workspace_form/fields/index.ts b/src/plugins/workspace/public/components/workspace_form/fields/index.ts new file mode 100644 index 000000000000..f9217e910213 --- /dev/null +++ b/src/plugins/workspace/public/components/workspace_form/fields/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export { WorkspaceDescriptionField } from './workspace_description_field'; +export { WorkspaceNameField } from './workspace_name_field'; diff --git a/src/plugins/workspace/public/components/workspace_form/index.ts b/src/plugins/workspace/public/components/workspace_form/index.ts index 42164ca530e2..3c493bf4aa3c 100644 --- a/src/plugins/workspace/public/components/workspace_form/index.ts +++ b/src/plugins/workspace/public/components/workspace_form/index.ts @@ -3,12 +3,30 @@ * SPDX-License-Identifier: Apache-2.0 */ -export { WorkspaceForm } from './workspace_form'; export { WorkspaceDetailForm } from './workspace_detail_form'; -export { WorkspaceFormSubmitData } from './types'; -export { WorkspaceOperationType } from './constants'; +export { SelectDataSourcePanel } from './select_data_source_panel'; +export { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; +export { WorkspaceUseCase } from './workspace_use_case'; +export { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; +export { WorkspaceCancelModal } from './workspace_cancel_modal'; +export { WorkspaceNameField, WorkspaceDescriptionField } from './fields'; + +export { WorkspaceFormSubmitData, WorkspaceFormProps, WorkspaceFormDataState } from './types'; +export { + WorkspaceOperationType, + DetailTab, + DetailTabTitles, + WorkspacePermissionItemType, + usersAndPermissionsCreatePageTitle, + selectDataSourceTitle, + workspaceDetailsTitle, + workspaceUseCaseTitle, +} from './constants'; export { convertPermissionsToPermissionSettings, convertPermissionSettingsToPermissions, } from './utils'; + export { WorkspaceFormProvider, useWorkspaceFormContext } from './workspace_form_context'; +export { useWorkspaceForm } from './use_workspace_form'; +export { useFormAvailableUseCases } from './use_form_available_use_cases'; diff --git a/src/plugins/workspace/public/components/workspace_form/types.ts b/src/plugins/workspace/public/components/workspace_form/types.ts index 5ec929e17b0c..2625047c2b69 100644 --- a/src/plugins/workspace/public/components/workspace_form/types.ts +++ b/src/plugins/workspace/public/components/workspace_form/types.ts @@ -31,17 +31,12 @@ export type WorkspacePermissionSetting = export interface WorkspaceFormSubmitData { name: string; description?: string; - features?: string[]; + features: string[]; color?: string; permissionSettings?: WorkspacePermissionSetting[]; selectedDataSources?: DataSource[]; } -export interface WorkspaceFormData extends WorkspaceFormSubmitData { - id: string; - reserved?: boolean; -} - export enum WorkspaceFormErrorCode { InvalidWorkspaceName, WorkspaceNameMissing, @@ -65,7 +60,7 @@ export interface WorkspaceFormError { export type WorkspaceFormErrors = { [key in keyof Omit< - WorkspaceFormData, + WorkspaceFormSubmitData, 'permissionSettings' | 'description' | 'selectedDataSources' >]?: WorkspaceFormError; } & { @@ -80,20 +75,24 @@ export interface WorkspaceFormProps { application: ApplicationStart; savedObjects: SavedObjectsStart; onSubmit?: (formData: WorkspaceFormSubmitData) => void; - defaultValues?: Partial; + defaultValues?: Partial; operationType: WorkspaceOperationType; permissionEnabled?: boolean; - detailTab?: DetailTab; dataSourceManagement?: DataSourceManagementPluginSetup; availableUseCases: WorkspaceUseCase[]; - detailTitle?: string; -} - -export interface WorkspaceDetailedFormProps extends WorkspaceFormProps { - defaultValues?: WorkspaceFormData; } export interface AvailableUseCaseItem extends Pick { disabled?: boolean; } + +export interface WorkspaceFormDataState + extends Omit { + name: string; + useCase: string | undefined; + selectedDataSources: DataSource[]; + permissionSettings: Array< + Pick & Partial + >; +} diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts index 6e25c81d4440..078ce9af3e45 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts @@ -8,10 +8,10 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { applicationServiceMock } from '../../../../../core/public/mocks'; import { WorkspacePermissionMode } from '../../../common/constants'; import { WorkspaceOperationType, WorkspacePermissionItemType } from './constants'; -import { WorkspaceFormData, WorkspaceFormErrorCode } from './types'; +import { WorkspaceFormSubmitData, WorkspaceFormErrorCode } from './types'; import { useWorkspaceForm } from './use_workspace_form'; -const setup = (defaultValues?: WorkspaceFormData, permissionEnabled = false) => { +const setup = (defaultValues?: WorkspaceFormSubmitData, permissionEnabled = false) => { const onSubmitMock = jest.fn(); const renderResult = renderHook(useWorkspaceForm, { initialProps: { diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts index f627df1f3aad..55f5c5af1607 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts @@ -13,7 +13,12 @@ import { isUseCaseFeatureConfig, } from '../../utils'; import { DataSource } from '../../../common/types'; -import { WorkspaceFormProps, WorkspaceFormErrors, WorkspacePermissionSetting } from './types'; +import { + WorkspaceFormProps, + WorkspaceFormErrors, + WorkspacePermissionSetting, + WorkspaceFormDataState, +} from './types'; import { generatePermissionSettingsState, getNumberOfChanges, @@ -46,7 +51,7 @@ export const useWorkspaceForm = ({ featureConfigs, ]); const [permissionSettings, setPermissionSettings] = useState< - Array & Partial> + WorkspaceFormDataState['permissionSettings'] >(initialPermissionSettingsRef.current); const [selectedDataSources, setSelectedDataSources] = useState( @@ -58,7 +63,7 @@ export const useWorkspaceForm = ({ const [formErrors, setFormErrors] = useState({}); const numberOfErrors = useMemo(() => getNumberOfErrors(formErrors), [formErrors]); const formIdRef = useRef(); - const getFormData = () => ({ + const getFormData = (): WorkspaceFormDataState => ({ name, description, features: featureConfigs, diff --git a/src/plugins/workspace/public/components/workspace_form/utils.ts b/src/plugins/workspace/public/components/workspace_form/utils.ts index 04c1f3772600..bd45cf6a901f 100644 --- a/src/plugins/workspace/public/components/workspace_form/utils.ts +++ b/src/plugins/workspace/public/components/workspace_form/utils.ts @@ -16,7 +16,7 @@ import { } from './constants'; import { - WorkspaceFormData, + WorkspaceFormDataState, WorkspaceFormError, WorkspaceFormErrorCode, WorkspaceFormErrors, @@ -295,11 +295,7 @@ export const isSelectedDataSourcesDuplicated = ( ) => selectedDataSources.some((ds) => ds.id === row.id); export const validateWorkspaceForm = ( - formData: Omit, 'permissionSettings'> & { - permissionSettings?: Array< - Pick & Partial - >; - }, + formData: Partial, isPermissionEnabled: boolean ) => { const formErrors: WorkspaceFormErrors = {}; @@ -452,12 +448,8 @@ const isSamePermissionSetting = (a: PermissionSettingLike, b: PermissionSettingL }; export const getNumberOfChanges = ( - newFormData: Partial> & { - permissionSettings?: Array< - Pick & Partial - >; - }, - initialFormData: Partial> + newFormData: Partial, + initialFormData: Partial ) => { let count = 0; if (newFormData.name !== initialFormData.name) { diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx index bc3ce92067ff..8b037a99ea63 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_detail_form.tsx @@ -50,7 +50,12 @@ const FormGroup = ({ title, children, describe }: FormGroupProps) => ( ); -export const WorkspaceDetailForm = (props: WorkspaceFormProps) => { +interface WorkspaceDetailedFormProps extends WorkspaceFormProps { + detailTab?: DetailTab; + detailTitle?: string; +} + +export const WorkspaceDetailForm = (props: WorkspaceDetailedFormProps) => { const { detailTab, detailTitle, defaultValues, availableUseCases } = props; const { formId, diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx deleted file mode 100644 index 0bd172e6c47a..000000000000 --- a/src/plugins/workspace/public/components/workspace_form/workspace_enter_details_panel.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { EuiColorPicker, EuiCompressedFormRow, EuiSpacer, EuiText } from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import React from 'react'; -import { EuiColorPickerOutput } from '@elastic/eui/src/components/color_picker/color_picker'; -import { WorkspaceFormErrors } from './types'; -import { WorkspaceNameField } from './fields/workspace_name_field'; -import { WorkspaceDescriptionField } from './fields/workspace_description_field'; - -export interface EnterDetailsPanelProps { - formErrors: WorkspaceFormErrors; - name?: string; - description?: string; - color?: string; - readOnly: boolean; - onNameChange: (newValue: string) => void; - onDescriptionChange: (newValue: string) => void; - handleColorChange: (text: string, output: EuiColorPickerOutput) => void; -} - -export const EnterDetailsPanel = ({ - formErrors, - name, - description, - color, - readOnly, - onNameChange, - onDescriptionChange, - handleColorChange, -}: EnterDetailsPanelProps) => { - return ( - <> - - - -
- - {i18n.translate('workspace.form.workspaceDetails.color.description', { - defaultMessage: 'Select a background color for the icon representing this workspace.', - })} - - - -
-
- - ); -}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx deleted file mode 100644 index f21a800a8357..000000000000 --- a/src/plugins/workspace/public/components/workspace_form/workspace_form.tsx +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React, { useCallback, useRef } from 'react'; -import { EuiPanel, EuiSpacer, EuiTitle, EuiForm, EuiText } from '@elastic/eui'; -import { i18n } from '@osd/i18n'; -import { WorkspaceFormProps } from './types'; -import { useWorkspaceForm } from './use_workspace_form'; -import { WorkspacePermissionSettingPanel } from './workspace_permission_setting_panel'; -import { WorkspaceUseCase } from './workspace_use_case'; -import { WorkspaceFormErrorCallout } from './workspace_form_error_callout'; -import { WorkspaceCreateActionPanel } from './workspace_create_action_panel'; -import { SelectDataSourcePanel } from './select_data_source_panel'; -import { EnterDetailsPanel } from './workspace_enter_details_panel'; -import { - selectDataSourceTitle, - usersAndPermissionsCreatePageTitle, - workspaceDetailsTitle, - workspaceUseCaseTitle, -} from './constants'; - -export const WorkspaceForm = (props: WorkspaceFormProps) => { - const { - application, - savedObjects, - defaultValues, - permissionEnabled, - dataSourceManagement: isDataSourceEnabled, - availableUseCases, - } = props; - const { - formId, - formData, - formErrors, - numberOfErrors, - setName, - setDescription, - handleFormSubmit, - handleColorChange, - handleUseCaseChange: handleUseCaseChangeInHook, - setPermissionSettings, - setSelectedDataSources, - } = useWorkspaceForm(props); - const nameManualChangedRef = useRef(false); - - const disabledUserOrGroupInputIdsRef = useRef( - defaultValues?.permissionSettings?.map((item) => item.id) ?? [] - ); - const isDashboardAdmin = application?.capabilities?.dashboards?.isDashboardAdmin ?? false; - const handleNameInputChange = useCallback( - (newName) => { - setName(newName); - nameManualChangedRef.current = true; - }, - [setName] - ); - const handleUseCaseChange = useCallback( - (newUseCase) => { - handleUseCaseChangeInHook(newUseCase); - const useCase = availableUseCases.find((item) => newUseCase === item.id); - if (!nameManualChangedRef.current && useCase) { - setName(useCase.title); - } - }, - [handleUseCaseChangeInHook, availableUseCases, setName] - ); - - return ( - - {numberOfErrors > 0 && ( - <> - - - - )} - - - -

{workspaceDetailsTitle}

-
- - -
- - - -

{workspaceUseCaseTitle}

-
- - -
- - {permissionEnabled && ( - - -

{usersAndPermissionsCreatePageTitle}

-
- - - {i18n.translate('workspace.form.usersAndPermissions.description', { - defaultMessage: - 'You will be added as an owner to the workspace. Select additional users and user groups as workspace collaborators with different access levels.', - })} - - - -
- )} - - - {/* SelectDataSourcePanel is only visible for dashboard admin and when data source is enabled*/} - {isDashboardAdmin && isDataSourceEnabled && ( - - -

{selectDataSourceTitle}

-
- -
- )} - - -
- ); -}; diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx index 24d1e7c80e64..5eebdc8fa369 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_use_case.tsx @@ -140,7 +140,6 @@ export const WorkspaceUseCase = ({ })} isInvalid={!!formErrors.features} error={formErrors.features?.message} - fullWidth > {availableUseCases.map(({ id, title, description, features, disabled }) => ( From 9438988f605ffeba1233db18161538c2de764c33 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 22:37:44 +0800 Subject: [PATCH 268/276] [workspace] refine style of workspace list table (#7913) (#7940) * fix, meet norms * 01-apply-new-standards * Changeset file for PR #7913 created/updated * Changeset file for PR #7913 created/updated * Changeset file for PR #7913 created/updated * Changeset file for PR #7913 created/updated --------- (cherry picked from commit 73765cd331e67c327877de14848e458159caad1a) Signed-off-by: Qxisylolo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7913.yml | 2 ++ .../__snapshots__/index.test.tsx.snap | 8 ++++---- .../public/components/workspace_list/index.tsx | 14 ++++++++------ 3 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/7913.yml diff --git a/changelogs/fragments/7913.yml b/changelogs/fragments/7913.yml new file mode 100644 index 000000000000..1ab0ce89f7f1 --- /dev/null +++ b/changelogs/fragments/7913.yml @@ -0,0 +1,2 @@ +fix: +- Refactor the style for the work list table ([#7913](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7913)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap b/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap index 0649f595b643..3c77bc87adc0 100644 --- a/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap +++ b/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap @@ -183,7 +183,7 @@ exports[`WorkspaceList should render title and table normally 1`] = `
+
+
+ +
+
+
+
- + - Use case + Last updated
+
+
+ +
+
+
+
- name1 +
- ID + Use case
- id1 + Analytics (All)
+ class="euiToolTipAnchor" + > +
+ should be able to see the description tooltip when hovering over the description +
+
- Use case + Last updated
- Analytics (All) + Aug 5, 1999 @ 22:00:00.000
- - - - Edit - - - - - - Delete - - +
+ + + +
+ +
+
+
+ +
+
+
+
- name2 +
- ID + Use case
- id2 + Observability
+ class="euiToolTipAnchor" + > +
+ should be able to see the description tooltip when hovering over the description +
+
- Use case + Last updated
+ > + Aug 5, 1999 @ 20:00:00.000 +
- - - - Edit - - - - - - Delete - - +
+ + + +
+ +
+
+
+ +
+
+
+
- name3 +
- ID + Use case
- id3 - + />
+ class="euiToolTipAnchor" + > +
+
- Use case + Last updated
- Observability + Aug 5, 1999 @ 21:00:00.000
- - - - Edit - - - - - - Delete - - +
+ + + +
+ +
- + ); diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx index a520196fa5bf..606052f5c92c 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.test.tsx @@ -8,21 +8,17 @@ import { fireEvent, render, screen } from '@testing-library/react'; import { WorkspaceMenu } from './workspace_menu'; import { coreMock } from '../../../../../core/public/mocks'; -import { CoreStart } from '../../../../../core/public'; +import { CoreStart, DEFAULT_NAV_GROUPS } from '../../../../../core/public'; import { BehaviorSubject } from 'rxjs'; import { IntlProvider } from 'react-intl'; import { recentWorkspaceManager } from '../../recent_workspace_manager'; -import { WORKSPACE_USE_CASES } from '../../../common/constants'; import * as workspaceUtils from '../utils/workspace'; describe('', () => { let coreStartMock: CoreStart; const navigateToApp = jest.fn(); const registeredUseCases$ = new BehaviorSubject([ - WORKSPACE_USE_CASES.observability, - WORKSPACE_USE_CASES['security-analytics'], - WORKSPACE_USE_CASES.essentials, - WORKSPACE_USE_CASES.search, + { ...DEFAULT_NAV_GROUPS.observability, features: [{ id: 'discover', title: 'Discover' }] }, ]); beforeEach(() => { diff --git a/src/plugins/workspace/public/mocks.ts b/src/plugins/workspace/public/mocks.ts new file mode 100644 index 000000000000..2f74bcf64835 --- /dev/null +++ b/src/plugins/workspace/public/mocks.ts @@ -0,0 +1,21 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { BehaviorSubject } from 'rxjs'; +import { WORKSPACE_USE_CASES } from '../common/constants'; + +export const createMockedRegisteredUseCases = () => + [ + WORKSPACE_USE_CASES.observability, + WORKSPACE_USE_CASES['security-analytics'], + WORKSPACE_USE_CASES.essentials, + WORKSPACE_USE_CASES.search, + ].map((item) => ({ + ...item, + features: item.features.map((id) => ({ id })), + })); + +export const createMockedRegisteredUseCases$ = () => + new BehaviorSubject(createMockedRegisteredUseCases()); diff --git a/src/plugins/workspace/public/plugin.test.ts b/src/plugins/workspace/public/plugin.test.ts index f3a5f48f33e8..ab33cd62d075 100644 --- a/src/plugins/workspace/public/plugin.test.ts +++ b/src/plugins/workspace/public/plugin.test.ts @@ -317,7 +317,7 @@ describe('Workspace plugin', () => { { id: 'foo', title: 'Foo', - features: ['system-feature'], + features: [{ id: 'system-feature', title: 'System feature' }], systematic: true, description: '', }, diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index a404132bc990..4731e9d205b7 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -134,7 +134,8 @@ export class WorkspacePlugin } if ( registeredUseCases.some( - (useCase) => useCase.systematic && useCase.features.includes(app.id) + (useCase) => + useCase.systematic && useCase.features.some((feature) => feature.id === app.id) ) ) { return; diff --git a/src/plugins/workspace/public/services/use_case_service.test.ts b/src/plugins/workspace/public/services/use_case_service.test.ts index 21049625d85e..00938fd7d60d 100644 --- a/src/plugins/workspace/public/services/use_case_service.test.ts +++ b/src/plugins/workspace/public/services/use_case_service.test.ts @@ -6,34 +6,43 @@ import { BehaviorSubject } from 'rxjs'; import { first } from 'rxjs/operators'; import { chromeServiceMock } from '../../../../core/public/mocks'; -import { NavGroupType } from '../../../../core/public'; +import { + ALL_USE_CASE_ID, + DEFAULT_NAV_GROUPS, + NavGroupItemInMap, + NavGroupType, +} from '../../../../core/public'; import { UseCaseService } from './use_case_service'; const mockNavGroupsMap = { system: { id: 'system', title: 'System', + description: 'System use case', navLinks: [], type: NavGroupType.SYSTEM, }, search: { id: 'search', title: 'Search', - navLinks: [{ id: 'searchRelevance' }], + description: 'Search use case', + navLinks: [{ id: 'searchRelevance', title: 'Search Relevance' }], order: 2000, }, observability: { id: 'observability', title: 'Observability', description: 'Observability description', - navLinks: [{ id: 'dashboards' }], + navLinks: [{ id: 'dashboards', title: 'Dashboards' }], order: 1000, }, }; const setupUseCaseStart = (options?: { navGroupEnabled?: boolean }) => { const chrome = chromeServiceMock.createStartContract(); - const workspaceConfigurableApps$ = new BehaviorSubject([{ id: 'searchRelevance' }]); - const navGroupsMap$ = new BehaviorSubject(mockNavGroupsMap); + const workspaceConfigurableApps$ = new BehaviorSubject([ + { id: 'searchRelevance', title: 'Search Relevance' }, + ]); + const navGroupsMap$ = new BehaviorSubject>(mockNavGroupsMap); const useCase = new UseCaseService(); chrome.navGroup.getNavGroupEnabled.mockImplementation(() => options?.navGroupEnabled ?? true); @@ -59,19 +68,24 @@ describe('UseCaseService', () => { }); const useCases = await useCaseStart.getRegisteredUseCases$().pipe(first()).toPromise(); - expect(useCases).toHaveLength(1); + expect(useCases).toHaveLength(2); expect(useCases).toEqual( expect.arrayContaining([ expect.objectContaining({ id: 'search', title: 'Search', - features: expect.arrayContaining(['searchRelevance']), + features: expect.arrayContaining([ + { id: 'searchRelevance', title: 'Search Relevance' }, + ]), + }), + expect.objectContaining({ + ...DEFAULT_NAV_GROUPS.all, }), ]) ); }); - it('should return registered use cases when nav group disabled', async () => { + it('should return registered use cases when nav group enabled', async () => { const { useCaseStart } = setupUseCaseStart(); const useCases = await useCaseStart.getRegisteredUseCases$().pipe(first()).toPromise(); @@ -79,12 +93,12 @@ describe('UseCaseService', () => { expect.objectContaining({ id: 'observability', title: 'Observability', - features: expect.arrayContaining(['dashboards']), + features: expect.arrayContaining([{ id: 'dashboards', title: 'Dashboards' }]), }), expect.objectContaining({ id: 'search', title: 'Search', - features: expect.arrayContaining(['searchRelevance']), + features: expect.arrayContaining([{ id: 'searchRelevance', title: 'Search Relevance' }]), }), expect.objectContaining({ id: 'system', @@ -97,10 +111,10 @@ describe('UseCaseService', () => { it('should not emit after navGroupsMap$ emit same value', async () => { const { useCaseStart, navGroupsMap$ } = setupUseCaseStart(); - const registeredUseCase$ = useCaseStart.getRegisteredUseCases$(); + const registeredUseCases$ = useCaseStart.getRegisteredUseCases$(); const fn = jest.fn(); - registeredUseCase$.subscribe(fn); + registeredUseCases$.subscribe(fn); expect(fn).toHaveBeenCalledTimes(1); @@ -116,5 +130,34 @@ describe('UseCaseService', () => { }); expect(fn).toHaveBeenCalledTimes(2); }); + it('should move all use case to the last one', async () => { + const { useCaseStart, navGroupsMap$ } = setupUseCaseStart(); + + navGroupsMap$.next({ + ...mockNavGroupsMap, + [ALL_USE_CASE_ID]: { ...DEFAULT_NAV_GROUPS.all, navLinks: [], order: -1 }, + }); + let useCases = await useCaseStart.getRegisteredUseCases$().pipe(first()).toPromise(); + + expect(useCases[useCases.length - 1]).toEqual( + expect.objectContaining({ + id: ALL_USE_CASE_ID, + systematic: true, + }) + ); + + navGroupsMap$.next({ + [ALL_USE_CASE_ID]: { ...DEFAULT_NAV_GROUPS.all, navLinks: [], order: 1500 }, + ...mockNavGroupsMap, + }); + useCases = await useCaseStart.getRegisteredUseCases$().pipe(first()).toPromise(); + + expect(useCases[useCases.length - 1]).toEqual( + expect.objectContaining({ + id: ALL_USE_CASE_ID, + systematic: true, + }) + ); + }); }); }); diff --git a/src/plugins/workspace/public/services/use_case_service.ts b/src/plugins/workspace/public/services/use_case_service.ts index ae127f08a5f2..681cf141327a 100644 --- a/src/plugins/workspace/public/services/use_case_service.ts +++ b/src/plugins/workspace/public/services/use_case_service.ts @@ -12,6 +12,8 @@ import { DEFAULT_APP_CATEGORIES, PublicAppInfo, WorkspacesSetup, + DEFAULT_NAV_GROUPS, + ALL_USE_CASE_ID, } from '../../../../core/public'; import { WORKSPACE_USE_CASES } from '../../common/constants'; import { @@ -19,6 +21,7 @@ import { getFirstUseCaseOfFeatureConfigs, isEqualWorkspaceUseCase, } from '../utils'; +import { WorkspaceUseCase } from '../types'; export interface UseCaseServiceSetupDeps { chrome: CoreSetup['chrome']; @@ -120,10 +123,18 @@ export class UseCaseService { ) .pipe( map((useCases) => - useCases.sort( - (a, b) => + useCases.sort((a, b) => { + // Make sure all use case should be the latest + if (a.id === ALL_USE_CASE_ID) { + return 1; + } + if (b.id === ALL_USE_CASE_ID) { + return -1; + } + return ( (a.order ?? Number.MAX_SAFE_INTEGER) - (b.order ?? Number.MAX_SAFE_INTEGER) - ) + ); + }) ) ); } @@ -137,9 +148,21 @@ export class UseCaseService { WORKSPACE_USE_CASES['security-analytics'], WORKSPACE_USE_CASES.essentials, WORKSPACE_USE_CASES.search, - ].filter((useCase) => { - return useCase.features.some((featureId) => configurableAppsId.includes(featureId)); - }); + ] + .filter((useCase) => { + return useCase.features.some((featureId) => configurableAppsId.includes(featureId)); + }) + .map((item) => ({ + ...item, + features: item.features.map((featureId) => ({ + title: configurableApps.find((app) => app.id === featureId)?.title, + id: featureId, + })), + })) + .concat({ + ...DEFAULT_NAV_GROUPS.all, + features: configurableApps.map((app) => ({ id: app.id, title: app.title })), + }) as WorkspaceUseCase[]; }) ); }, diff --git a/src/plugins/workspace/public/types.ts b/src/plugins/workspace/public/types.ts index d5cfc224416f..2fc342c0f8c3 100644 --- a/src/plugins/workspace/public/types.ts +++ b/src/plugins/workspace/public/types.ts @@ -18,7 +18,7 @@ export interface WorkspaceUseCase { id: string; title: string; description: string; - features: string[]; + features: Array<{ id: string; title?: string }>; systematic?: boolean; order?: number; } diff --git a/src/plugins/workspace/public/utils.test.ts b/src/plugins/workspace/public/utils.test.ts index 4e0146b39ad6..6f599084f9db 100644 --- a/src/plugins/workspace/public/utils.test.ts +++ b/src/plugins/workspace/public/utils.test.ts @@ -19,21 +19,17 @@ import { } from './utils'; import { WorkspaceAvailability } from '../../../core/public'; import { coreMock } from '../../../core/public/mocks'; -import { WORKSPACE_DETAIL_APP_ID, WORKSPACE_USE_CASES } from '../common/constants'; +import { WORKSPACE_DETAIL_APP_ID } from '../common/constants'; import { SigV4ServiceName } from '../../../plugins/data_source/common/data_sources'; +import { createMockedRegisteredUseCases } from './mocks'; const startMock = coreMock.createStart(); -const STATIC_USE_CASES = [ - WORKSPACE_USE_CASES.observability, - WORKSPACE_USE_CASES['security-analytics'], - WORKSPACE_USE_CASES.search, - WORKSPACE_USE_CASES.essentials, -]; +const STATIC_USE_CASES = createMockedRegisteredUseCases(); const useCaseMock = { id: 'foo', title: 'Foo', description: 'Foo description', - features: ['bar'], + features: [{ id: 'bar' }], systematic: false, order: 1, }; @@ -349,7 +345,7 @@ describe('workspace utils: isFeatureIdInsideUseCase', () => { id: 'foo', title: 'Foo', description: 'Foo description', - features: ['discover'], + features: [{ id: 'discover' }], }, ]) ).toBe(true); @@ -469,13 +465,13 @@ describe('workspace utils: convertNavGroupToWorkspaceUseCase', () => { id: 'foo', title: 'Foo', description: 'Foo description', - navLinks: [{ id: 'bar' }], + navLinks: [{ id: 'bar', title: 'Bar' }], }) ).toEqual({ id: 'foo', title: 'Foo', description: 'Foo description', - features: ['bar'], + features: [{ id: 'bar', title: 'Bar' }], systematic: false, }); @@ -484,14 +480,14 @@ describe('workspace utils: convertNavGroupToWorkspaceUseCase', () => { id: 'foo', title: 'Foo', description: 'Foo description', - navLinks: [{ id: 'bar' }], + navLinks: [{ id: 'bar', title: 'Bar' }], type: NavGroupType.SYSTEM, }) ).toEqual({ id: 'foo', title: 'Foo', description: 'Foo description', - features: ['bar'], + features: [{ id: 'bar', title: 'Bar' }], systematic: true, }); }); @@ -546,11 +542,19 @@ describe('workspace utils: isEqualWorkspaceUseCase', () => { }) ).toEqual(false); }); - it('should return false when features content not equal', () => { + it('should return false when features id not equal', () => { expect( isEqualWorkspaceUseCase(useCaseMock, { ...useCaseMock, - features: ['baz'], + features: [{ id: 'baz' }], + }) + ).toEqual(false); + }); + it('should return false when features title not equal', () => { + expect( + isEqualWorkspaceUseCase(useCaseMock, { + ...useCaseMock, + features: [{ id: 'bar', title: 'Baz' }], }) ).toEqual(false); }); diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index d57cacde7684..2bc4f7a80155 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -48,7 +48,7 @@ export const isFeatureIdInsideUseCase = ( useCases: WorkspaceUseCase[] ) => { const availableFeatures = useCases.find(({ id }) => id === useCaseId)?.features ?? []; - return availableFeatures.includes(featureId); + return availableFeatures.some((feature) => feature.id === featureId); }; export const isNavGroupInFeatureConfigs = (navGroupId: string, featureConfigs: string[]) => @@ -255,7 +255,7 @@ export const convertNavGroupToWorkspaceUseCase = ({ id, title, description, - features: navLinks.map((item) => item.id), + features: navLinks.map((item) => ({ id: item.id, title: item.title })), systematic: type === NavGroupType.SYSTEM || id === ALL_USE_CASE_ID, order, }); @@ -278,7 +278,11 @@ export const isEqualWorkspaceUseCase = (a: WorkspaceUseCase, b: WorkspaceUseCase } if ( a.features.length !== b.features.length || - a.features.some((featureId) => !b.features.includes(featureId)) + a.features.some((aFeature) => + b.features.some( + (bFeature) => aFeature.id !== bFeature.id || aFeature.title !== bFeature.title + ) + ) ) { return false; } @@ -377,7 +381,7 @@ export const getUseCaseUrl = ( http: HttpSetup ): string => { const appId = - (useCase?.id !== ALL_USE_CASE_ID && useCase?.features?.[0]) || WORKSPACE_DETAIL_APP_ID; + (useCase?.id !== ALL_USE_CASE_ID && useCase?.features?.[0].id) || WORKSPACE_DETAIL_APP_ID; const useCaseURL = formatUrlWithWorkspaceId( application.getUrlForApp(appId, { absolute: false, From 458e8592debb88b7272a880904ba2fd726cb3cf3 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 17:59:53 +0800 Subject: [PATCH 241/276] [Workspace]Fix maximum call stack error in use case service (#7817) (#7840) * Fix maximum call stack error in UseCaseService * Changeset file for PR #7817 created/updated * Improve UT coverage * Refactor compare with sort * Refactor compareFeatures * Add ut for multi same features --------- (cherry picked from commit 452b65dceff7c9a2f283f0dda0793d0a4a8f3aba) Signed-off-by: Lin Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7817.yml | 2 ++ src/plugins/workspace/public/types.ts | 7 ++++- src/plugins/workspace/public/utils.test.ts | 32 ++++++++++++++++++++++ src/plugins/workspace/public/utils.ts | 23 ++++++++++------ 4 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 changelogs/fragments/7817.yml diff --git a/changelogs/fragments/7817.yml b/changelogs/fragments/7817.yml new file mode 100644 index 000000000000..1b2a2607f264 --- /dev/null +++ b/changelogs/fragments/7817.yml @@ -0,0 +1,2 @@ +fix: +- [Workspace] maximum call stack error in use case service ([#7817](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7817)) \ No newline at end of file diff --git a/src/plugins/workspace/public/types.ts b/src/plugins/workspace/public/types.ts index 2fc342c0f8c3..8e5076a6cca7 100644 --- a/src/plugins/workspace/public/types.ts +++ b/src/plugins/workspace/public/types.ts @@ -14,11 +14,16 @@ export type Services = CoreStart & { navigationUI?: NavigationPublicPluginStart['ui']; }; +export interface WorkspaceUseCaseFeature { + id: string; + title?: string; +} + export interface WorkspaceUseCase { id: string; title: string; description: string; - features: Array<{ id: string; title?: string }>; + features: WorkspaceUseCaseFeature[]; systematic?: boolean; order?: number; } diff --git a/src/plugins/workspace/public/utils.test.ts b/src/plugins/workspace/public/utils.test.ts index 6f599084f9db..03aa0e208222 100644 --- a/src/plugins/workspace/public/utils.test.ts +++ b/src/plugins/workspace/public/utils.test.ts @@ -558,6 +558,38 @@ describe('workspace utils: isEqualWorkspaceUseCase', () => { }) ).toEqual(false); }); + it('should return false for duplicate features', () => { + expect( + isEqualWorkspaceUseCase( + { ...useCaseMock, features: [useCaseMock.features[0], useCaseMock.features[0]] }, + { + ...useCaseMock, + features: [ + useCaseMock.features[0], + { + id: 'another', + title: 'Another', + }, + ], + } + ) + ).toEqual(false); + }); + it('should return true for multi same features', () => { + const anotherFeature = { + id: 'another', + title: 'Another', + }; + expect( + isEqualWorkspaceUseCase( + { ...useCaseMock, features: [useCaseMock.features[0], anotherFeature] }, + { + ...useCaseMock, + features: [useCaseMock.features[0], anotherFeature], + } + ) + ).toEqual(true); + }); it('should return true when all properties equal', () => { expect( isEqualWorkspaceUseCase(useCaseMock, { diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index 2bc4f7a80155..bbadd528d73d 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -24,7 +24,7 @@ import { WorkspaceAvailability, } from '../../../core/public'; import { DEFAULT_SELECTED_FEATURES_IDS, WORKSPACE_DETAIL_APP_ID } from '../common/constants'; -import { WorkspaceUseCase } from './types'; +import { WorkspaceUseCase, WorkspaceUseCaseFeature } from './types'; import { formatUrlWithWorkspaceId } from '../../../core/public/utils'; import { SigV4ServiceName } from '../../../plugins/data_source/common/data_sources'; @@ -260,6 +260,18 @@ export const convertNavGroupToWorkspaceUseCase = ({ order, }); +const compareFeatures = ( + features1: WorkspaceUseCaseFeature[], + features2: WorkspaceUseCaseFeature[] +) => { + const featuresSerializer = (features: WorkspaceUseCaseFeature[]) => + features + .map(({ id, title }) => `${id}-${title}`) + .sort() + .join(); + return featuresSerializer(features1) === featuresSerializer(features2); +}; + export const isEqualWorkspaceUseCase = (a: WorkspaceUseCase, b: WorkspaceUseCase) => { if (a.id !== b.id) { return false; @@ -276,14 +288,7 @@ export const isEqualWorkspaceUseCase = (a: WorkspaceUseCase, b: WorkspaceUseCase if (a.order !== b.order) { return false; } - if ( - a.features.length !== b.features.length || - a.features.some((aFeature) => - b.features.some( - (bFeature) => aFeature.id !== bFeature.id || aFeature.title !== bFeature.title - ) - ) - ) { + if (a.features.length !== b.features.length || !compareFeatures(a.features, b.features)) { return false; } return true; From ef49f5b8eedd85d096d21c4df343383def703b47 Mon Sep 17 00:00:00 2001 From: SuZhou-Joe Date: Tue, 27 Aug 2024 10:36:22 +0800 Subject: [PATCH 242/276] [Backport 2.x][navigation]feat: add home icon in left bottom (#7802) (#7836) * [navigation]feat: add home icon in left bottom (#7802) * feat: add home icon in left bottom Signed-off-by: SuZhou-Joe * feat: remove useless padding Signed-off-by: SuZhou-Joe * Changeset file for PR #7802 created/updated * fix: update snapshot Signed-off-by: SuZhou-Joe * feat: use flush Signed-off-by: SuZhou-Joe * feat: optimize style Signed-off-by: SuZhou-Joe * feat: move features around in nav group Signed-off-by: SuZhou-Joe * fix: typo Signed-off-by: SuZhou-Joe * fix: unit test Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> (cherry picked from commit 106b64cd1e85df979fa8b78269b25f10057d284c) * fix: unit test error Signed-off-by: SuZhou-Joe --------- Signed-off-by: SuZhou-Joe --- changelogs/fragments/7802.yml | 2 + packages/osd-pm/dist/index.js | 1628 ++++++++--------- ...ollapsible_nav_group_enabled.test.tsx.snap | 8 +- .../header/collapsible_nav_group_enabled.scss | 1 + .../header/collapsible_nav_group_enabled.tsx | 1 + .../application/components/home_icon.test.tsx | 19 + .../application/components/home_icon.tsx | 20 + src/plugins/home/public/plugin.ts | 26 +- .../saved_objects_management/public/plugin.ts | 2 +- src/plugins/visualize/public/plugin.ts | 13 +- .../workspace_menu/workspace_menu.tsx | 7 +- src/plugins/workspace/public/plugin.test.ts | 18 +- src/plugins/workspace/public/plugin.ts | 29 +- .../public/services/use_case_service.test.ts | 53 +- .../public/services/use_case_service.ts | 11 +- 15 files changed, 962 insertions(+), 876 deletions(-) create mode 100644 changelogs/fragments/7802.yml create mode 100644 src/plugins/home/public/application/components/home_icon.test.tsx create mode 100644 src/plugins/home/public/application/components/home_icon.tsx diff --git a/changelogs/fragments/7802.yml b/changelogs/fragments/7802.yml new file mode 100644 index 000000000000..2937e55931ae --- /dev/null +++ b/changelogs/fragments/7802.yml @@ -0,0 +1,2 @@ +feat: +- Add home icon in left bottom ([#7802](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7802)) \ No newline at end of file diff --git a/packages/osd-pm/dist/index.js b/packages/osd-pm/dist/index.js index cf943af712b0..e3c3250acb68 100644 --- a/packages/osd-pm/dist/index.js +++ b/packages/osd-pm/dist/index.js @@ -735,245 +735,245 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__importDefault", function() { return __importDefault; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__classPrivateFieldGet", function() { return __classPrivateFieldGet; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__classPrivateFieldSet", function() { return __classPrivateFieldSet; }); -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ -/* global Reflect, Promise */ - -var extendStatics = function(d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; - return extendStatics(d, b); -}; - -function __extends(d, b) { - if (typeof b !== "function" && b !== null) - throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -} - -var __assign = function() { - __assign = Object.assign || function __assign(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; - } - return t; - } - return __assign.apply(this, arguments); -} - -function __rest(s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; -} - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -} - -function __param(paramIndex, decorator) { - return function (target, key) { decorator(target, key, paramIndex); } -} - -function __metadata(metadataKey, metadataValue) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); -} - -function __awaiter(thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -} - -function __generator(thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -} - -var __createBinding = Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -}); - -function __exportStar(m, o) { - for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); -} - -function __values(o) { - var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; - if (m) return m.call(o); - if (o && typeof o.length === "number") return { - next: function () { - if (o && i >= o.length) o = void 0; - return { value: o && o[i++], done: !o }; - } - }; - throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); -} - -function __read(o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); - } - catch (error) { e = { error: error }; } - finally { - try { - if (r && !r.done && (m = i["return"])) m.call(i); - } - finally { if (e) throw e.error; } - } - return ar; -} - -/** @deprecated */ -function __spread() { - for (var ar = [], i = 0; i < arguments.length; i++) - ar = ar.concat(__read(arguments[i])); - return ar; -} - -/** @deprecated */ -function __spreadArrays() { - for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; - for (var r = Array(s), k = 0, i = 0; i < il; i++) - for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) - r[k] = a[j]; - return r; -} - -function __spreadArray(to, from, pack) { - if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { - if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || Array.prototype.slice.call(from)); -} - -function __await(v) { - return this instanceof __await ? (this.v = v, this) : new __await(v); -} - -function __asyncGenerator(thisArg, _arguments, generator) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var g = generator.apply(thisArg, _arguments || []), i, q = []; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; - function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } - function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } - function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } - function fulfill(value) { resume("next", value); } - function reject(value) { resume("throw", value); } - function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } -} - -function __asyncDelegator(o) { - var i, p; - return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } -} - -function __asyncValues(o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } -} - -function __makeTemplateObject(cooked, raw) { - if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } - return cooked; -}; - -var __setModuleDefault = Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}; - -function __importStar(mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -} - -function __importDefault(mod) { - return (mod && mod.__esModule) ? mod : { default: mod }; -} - -function __classPrivateFieldGet(receiver, state, kind, f) { - if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); - if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); - return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); -} - -function __classPrivateFieldSet(receiver, state, value, kind, f) { - if (kind === "m") throw new TypeError("Private method is not writable"); - if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); - if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); - return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; -} +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +function __extends(d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + } + return __assign.apply(this, arguments); +} + +function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +} + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +function __param(paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +} + +function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +var __createBinding = Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +}); + +function __exportStar(m, o) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); +} + +function __values(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +} + +function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +} + +/** @deprecated */ +function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; +} + +/** @deprecated */ +function __spreadArrays() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +} + +function __spreadArray(to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +} + +function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } +} + +function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +} + +function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; + +var __setModuleDefault = Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}; + +function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +} + +function __importDefault(mod) { + return (mod && mod.__esModule) ? mod : { default: mod }; +} + +function __classPrivateFieldGet(receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +} + +function __classPrivateFieldSet(receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +} /***/ }), @@ -1653,224 +1653,224 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__importDefault", function() { return __importDefault; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__classPrivateFieldGet", function() { return __classPrivateFieldGet; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "__classPrivateFieldSet", function() { return __classPrivateFieldSet; }); -/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ -/* global Reflect, Promise */ - -var extendStatics = function(d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); -}; - -function __extends(d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -} - -var __assign = function() { - __assign = Object.assign || function __assign(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; - } - return t; - } - return __assign.apply(this, arguments); -} - -function __rest(s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; -} - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; -} - -function __param(paramIndex, decorator) { - return function (target, key) { decorator(target, key, paramIndex); } -} - -function __metadata(metadataKey, metadataValue) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); -} - -function __awaiter(thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -} - -function __generator(thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -} - -function __createBinding(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -} - -function __exportStar(m, exports) { - for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) exports[p] = m[p]; -} - -function __values(o) { - var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; - if (m) return m.call(o); - if (o && typeof o.length === "number") return { - next: function () { - if (o && i >= o.length) o = void 0; - return { value: o && o[i++], done: !o }; - } - }; - throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); -} - -function __read(o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); - } - catch (error) { e = { error: error }; } - finally { - try { - if (r && !r.done && (m = i["return"])) m.call(i); - } - finally { if (e) throw e.error; } - } - return ar; -} - -function __spread() { - for (var ar = [], i = 0; i < arguments.length; i++) - ar = ar.concat(__read(arguments[i])); - return ar; -} - -function __spreadArrays() { - for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; - for (var r = Array(s), k = 0, i = 0; i < il; i++) - for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) - r[k] = a[j]; - return r; -}; - -function __await(v) { - return this instanceof __await ? (this.v = v, this) : new __await(v); -} - -function __asyncGenerator(thisArg, _arguments, generator) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var g = generator.apply(thisArg, _arguments || []), i, q = []; - return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; - function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } - function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } - function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } - function fulfill(value) { resume("next", value); } - function reject(value) { resume("throw", value); } - function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } -} - -function __asyncDelegator(o) { - var i, p; - return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; - function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } -} - -function __asyncValues(o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } -} - -function __makeTemplateObject(cooked, raw) { - if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } - return cooked; -}; - -function __importStar(mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; - result.default = mod; - return result; -} - -function __importDefault(mod) { - return (mod && mod.__esModule) ? mod : { default: mod }; -} - -function __classPrivateFieldGet(receiver, privateMap) { - if (!privateMap.has(receiver)) { - throw new TypeError("attempted to get private field on non-instance"); - } - return privateMap.get(receiver); -} - -function __classPrivateFieldSet(receiver, privateMap, value) { - if (!privateMap.has(receiver)) { - throw new TypeError("attempted to set private field on non-instance"); - } - privateMap.set(receiver, value); - return value; -} +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + } + return __assign.apply(this, arguments); +} + +function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +} + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +function __param(paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +} + +function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +function __createBinding(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +} + +function __exportStar(m, exports) { + for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) exports[p] = m[p]; +} + +function __values(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +} + +function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +} + +function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; +} + +function __spreadArrays() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; + +function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } +} + +function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +} + +function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; + +function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result.default = mod; + return result; +} + +function __importDefault(mod) { + return (mod && mod.__esModule) ? mod : { default: mod }; +} + +function __classPrivateFieldGet(receiver, privateMap) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to get private field on non-instance"); + } + return privateMap.get(receiver); +} + +function __classPrivateFieldSet(receiver, privateMap, value) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to set private field on non-instance"); + } + privateMap.set(receiver, value); + return value; +} /***/ }), @@ -8252,158 +8252,158 @@ convert.rgb.gray = function (rgb) { /***/ (function(module, exports, __webpack_require__) { "use strict"; - - -module.exports = { - "aliceblue": [240, 248, 255], - "antiquewhite": [250, 235, 215], - "aqua": [0, 255, 255], - "aquamarine": [127, 255, 212], - "azure": [240, 255, 255], - "beige": [245, 245, 220], - "bisque": [255, 228, 196], - "black": [0, 0, 0], - "blanchedalmond": [255, 235, 205], - "blue": [0, 0, 255], - "blueviolet": [138, 43, 226], - "brown": [165, 42, 42], - "burlywood": [222, 184, 135], - "cadetblue": [95, 158, 160], - "chartreuse": [127, 255, 0], - "chocolate": [210, 105, 30], - "coral": [255, 127, 80], - "cornflowerblue": [100, 149, 237], - "cornsilk": [255, 248, 220], - "crimson": [220, 20, 60], - "cyan": [0, 255, 255], - "darkblue": [0, 0, 139], - "darkcyan": [0, 139, 139], - "darkgoldenrod": [184, 134, 11], - "darkgray": [169, 169, 169], - "darkgreen": [0, 100, 0], - "darkgrey": [169, 169, 169], - "darkkhaki": [189, 183, 107], - "darkmagenta": [139, 0, 139], - "darkolivegreen": [85, 107, 47], - "darkorange": [255, 140, 0], - "darkorchid": [153, 50, 204], - "darkred": [139, 0, 0], - "darksalmon": [233, 150, 122], - "darkseagreen": [143, 188, 143], - "darkslateblue": [72, 61, 139], - "darkslategray": [47, 79, 79], - "darkslategrey": [47, 79, 79], - "darkturquoise": [0, 206, 209], - "darkviolet": [148, 0, 211], - "deeppink": [255, 20, 147], - "deepskyblue": [0, 191, 255], - "dimgray": [105, 105, 105], - "dimgrey": [105, 105, 105], - "dodgerblue": [30, 144, 255], - "firebrick": [178, 34, 34], - "floralwhite": [255, 250, 240], - "forestgreen": [34, 139, 34], - "fuchsia": [255, 0, 255], - "gainsboro": [220, 220, 220], - "ghostwhite": [248, 248, 255], - "gold": [255, 215, 0], - "goldenrod": [218, 165, 32], - "gray": [128, 128, 128], - "green": [0, 128, 0], - "greenyellow": [173, 255, 47], - "grey": [128, 128, 128], - "honeydew": [240, 255, 240], - "hotpink": [255, 105, 180], - "indianred": [205, 92, 92], - "indigo": [75, 0, 130], - "ivory": [255, 255, 240], - "khaki": [240, 230, 140], - "lavender": [230, 230, 250], - "lavenderblush": [255, 240, 245], - "lawngreen": [124, 252, 0], - "lemonchiffon": [255, 250, 205], - "lightblue": [173, 216, 230], - "lightcoral": [240, 128, 128], - "lightcyan": [224, 255, 255], - "lightgoldenrodyellow": [250, 250, 210], - "lightgray": [211, 211, 211], - "lightgreen": [144, 238, 144], - "lightgrey": [211, 211, 211], - "lightpink": [255, 182, 193], - "lightsalmon": [255, 160, 122], - "lightseagreen": [32, 178, 170], - "lightskyblue": [135, 206, 250], - "lightslategray": [119, 136, 153], - "lightslategrey": [119, 136, 153], - "lightsteelblue": [176, 196, 222], - "lightyellow": [255, 255, 224], - "lime": [0, 255, 0], - "limegreen": [50, 205, 50], - "linen": [250, 240, 230], - "magenta": [255, 0, 255], - "maroon": [128, 0, 0], - "mediumaquamarine": [102, 205, 170], - "mediumblue": [0, 0, 205], - "mediumorchid": [186, 85, 211], - "mediumpurple": [147, 112, 219], - "mediumseagreen": [60, 179, 113], - "mediumslateblue": [123, 104, 238], - "mediumspringgreen": [0, 250, 154], - "mediumturquoise": [72, 209, 204], - "mediumvioletred": [199, 21, 133], - "midnightblue": [25, 25, 112], - "mintcream": [245, 255, 250], - "mistyrose": [255, 228, 225], - "moccasin": [255, 228, 181], - "navajowhite": [255, 222, 173], - "navy": [0, 0, 128], - "oldlace": [253, 245, 230], - "olive": [128, 128, 0], - "olivedrab": [107, 142, 35], - "orange": [255, 165, 0], - "orangered": [255, 69, 0], - "orchid": [218, 112, 214], - "palegoldenrod": [238, 232, 170], - "palegreen": [152, 251, 152], - "paleturquoise": [175, 238, 238], - "palevioletred": [219, 112, 147], - "papayawhip": [255, 239, 213], - "peachpuff": [255, 218, 185], - "peru": [205, 133, 63], - "pink": [255, 192, 203], - "plum": [221, 160, 221], - "powderblue": [176, 224, 230], - "purple": [128, 0, 128], - "rebeccapurple": [102, 51, 153], - "red": [255, 0, 0], - "rosybrown": [188, 143, 143], - "royalblue": [65, 105, 225], - "saddlebrown": [139, 69, 19], - "salmon": [250, 128, 114], - "sandybrown": [244, 164, 96], - "seagreen": [46, 139, 87], - "seashell": [255, 245, 238], - "sienna": [160, 82, 45], - "silver": [192, 192, 192], - "skyblue": [135, 206, 235], - "slateblue": [106, 90, 205], - "slategray": [112, 128, 144], - "slategrey": [112, 128, 144], - "snow": [255, 250, 250], - "springgreen": [0, 255, 127], - "steelblue": [70, 130, 180], - "tan": [210, 180, 140], - "teal": [0, 128, 128], - "thistle": [216, 191, 216], - "tomato": [255, 99, 71], - "turquoise": [64, 224, 208], - "violet": [238, 130, 238], - "wheat": [245, 222, 179], - "white": [255, 255, 255], - "whitesmoke": [245, 245, 245], - "yellow": [255, 255, 0], - "yellowgreen": [154, 205, 50] -}; + + +module.exports = { + "aliceblue": [240, 248, 255], + "antiquewhite": [250, 235, 215], + "aqua": [0, 255, 255], + "aquamarine": [127, 255, 212], + "azure": [240, 255, 255], + "beige": [245, 245, 220], + "bisque": [255, 228, 196], + "black": [0, 0, 0], + "blanchedalmond": [255, 235, 205], + "blue": [0, 0, 255], + "blueviolet": [138, 43, 226], + "brown": [165, 42, 42], + "burlywood": [222, 184, 135], + "cadetblue": [95, 158, 160], + "chartreuse": [127, 255, 0], + "chocolate": [210, 105, 30], + "coral": [255, 127, 80], + "cornflowerblue": [100, 149, 237], + "cornsilk": [255, 248, 220], + "crimson": [220, 20, 60], + "cyan": [0, 255, 255], + "darkblue": [0, 0, 139], + "darkcyan": [0, 139, 139], + "darkgoldenrod": [184, 134, 11], + "darkgray": [169, 169, 169], + "darkgreen": [0, 100, 0], + "darkgrey": [169, 169, 169], + "darkkhaki": [189, 183, 107], + "darkmagenta": [139, 0, 139], + "darkolivegreen": [85, 107, 47], + "darkorange": [255, 140, 0], + "darkorchid": [153, 50, 204], + "darkred": [139, 0, 0], + "darksalmon": [233, 150, 122], + "darkseagreen": [143, 188, 143], + "darkslateblue": [72, 61, 139], + "darkslategray": [47, 79, 79], + "darkslategrey": [47, 79, 79], + "darkturquoise": [0, 206, 209], + "darkviolet": [148, 0, 211], + "deeppink": [255, 20, 147], + "deepskyblue": [0, 191, 255], + "dimgray": [105, 105, 105], + "dimgrey": [105, 105, 105], + "dodgerblue": [30, 144, 255], + "firebrick": [178, 34, 34], + "floralwhite": [255, 250, 240], + "forestgreen": [34, 139, 34], + "fuchsia": [255, 0, 255], + "gainsboro": [220, 220, 220], + "ghostwhite": [248, 248, 255], + "gold": [255, 215, 0], + "goldenrod": [218, 165, 32], + "gray": [128, 128, 128], + "green": [0, 128, 0], + "greenyellow": [173, 255, 47], + "grey": [128, 128, 128], + "honeydew": [240, 255, 240], + "hotpink": [255, 105, 180], + "indianred": [205, 92, 92], + "indigo": [75, 0, 130], + "ivory": [255, 255, 240], + "khaki": [240, 230, 140], + "lavender": [230, 230, 250], + "lavenderblush": [255, 240, 245], + "lawngreen": [124, 252, 0], + "lemonchiffon": [255, 250, 205], + "lightblue": [173, 216, 230], + "lightcoral": [240, 128, 128], + "lightcyan": [224, 255, 255], + "lightgoldenrodyellow": [250, 250, 210], + "lightgray": [211, 211, 211], + "lightgreen": [144, 238, 144], + "lightgrey": [211, 211, 211], + "lightpink": [255, 182, 193], + "lightsalmon": [255, 160, 122], + "lightseagreen": [32, 178, 170], + "lightskyblue": [135, 206, 250], + "lightslategray": [119, 136, 153], + "lightslategrey": [119, 136, 153], + "lightsteelblue": [176, 196, 222], + "lightyellow": [255, 255, 224], + "lime": [0, 255, 0], + "limegreen": [50, 205, 50], + "linen": [250, 240, 230], + "magenta": [255, 0, 255], + "maroon": [128, 0, 0], + "mediumaquamarine": [102, 205, 170], + "mediumblue": [0, 0, 205], + "mediumorchid": [186, 85, 211], + "mediumpurple": [147, 112, 219], + "mediumseagreen": [60, 179, 113], + "mediumslateblue": [123, 104, 238], + "mediumspringgreen": [0, 250, 154], + "mediumturquoise": [72, 209, 204], + "mediumvioletred": [199, 21, 133], + "midnightblue": [25, 25, 112], + "mintcream": [245, 255, 250], + "mistyrose": [255, 228, 225], + "moccasin": [255, 228, 181], + "navajowhite": [255, 222, 173], + "navy": [0, 0, 128], + "oldlace": [253, 245, 230], + "olive": [128, 128, 0], + "olivedrab": [107, 142, 35], + "orange": [255, 165, 0], + "orangered": [255, 69, 0], + "orchid": [218, 112, 214], + "palegoldenrod": [238, 232, 170], + "palegreen": [152, 251, 152], + "paleturquoise": [175, 238, 238], + "palevioletred": [219, 112, 147], + "papayawhip": [255, 239, 213], + "peachpuff": [255, 218, 185], + "peru": [205, 133, 63], + "pink": [255, 192, 203], + "plum": [221, 160, 221], + "powderblue": [176, 224, 230], + "purple": [128, 0, 128], + "rebeccapurple": [102, 51, 153], + "red": [255, 0, 0], + "rosybrown": [188, 143, 143], + "royalblue": [65, 105, 225], + "saddlebrown": [139, 69, 19], + "salmon": [250, 128, 114], + "sandybrown": [244, 164, 96], + "seagreen": [46, 139, 87], + "seashell": [255, 245, 238], + "sienna": [160, 82, 45], + "silver": [192, 192, 192], + "skyblue": [135, 206, 235], + "slateblue": [106, 90, 205], + "slategray": [112, 128, 144], + "slategrey": [112, 128, 144], + "snow": [255, 250, 250], + "springgreen": [0, 255, 127], + "steelblue": [70, 130, 180], + "tan": [210, 180, 140], + "teal": [0, 128, 128], + "thistle": [216, 191, 216], + "tomato": [255, 99, 71], + "turquoise": [64, 224, 208], + "violet": [238, 130, 238], + "wheat": [245, 222, 179], + "white": [255, 255, 255], + "whitesmoke": [245, 245, 245], + "yellow": [255, 255, 0], + "yellowgreen": [154, 205, 50] +}; /***/ }), @@ -10741,58 +10741,58 @@ mkdirP.sync = function sync (p, opts, made) { /* 142 */ /***/ (function(module, exports) { -exports.replaceDollarWithPercentPair = replaceDollarWithPercentPair -exports.convertToSetCommand = convertToSetCommand -exports.convertToSetCommands = convertToSetCommands - -function convertToSetCommand(key, value) { - var line = "" - key = key || "" - key = key.trim() - value = value || "" - value = value.trim() - if(key && value && value.length > 0) { - line = "@SET " + key + "=" + replaceDollarWithPercentPair(value) + "\r\n" - } - return line -} - -function extractVariableValuePairs(declarations) { - var pairs = {} - declarations.map(function(declaration) { - var split = declaration.split("=") - pairs[split[0]]=split[1] - }) - return pairs -} - -function convertToSetCommands(variableString) { - var variableValuePairs = extractVariableValuePairs(variableString.split(" ")) - var variableDeclarationsAsBatch = "" - Object.keys(variableValuePairs).forEach(function (key) { - variableDeclarationsAsBatch += convertToSetCommand(key, variableValuePairs[key]) - }) - return variableDeclarationsAsBatch -} - -function replaceDollarWithPercentPair(value) { - var dollarExpressions = /\$\{?([^\$@#\?\- \t{}:]+)\}?/g - var result = "" - var startIndex = 0 - value = value || "" - do { - var match = dollarExpressions.exec(value) - if(match) { - var betweenMatches = value.substring(startIndex, match.index) || "" - result += betweenMatches + "%" + match[1] + "%" - startIndex = dollarExpressions.lastIndex - } - } while (dollarExpressions.lastIndex > 0) - result += value.substr(startIndex) - return result -} - - +exports.replaceDollarWithPercentPair = replaceDollarWithPercentPair +exports.convertToSetCommand = convertToSetCommand +exports.convertToSetCommands = convertToSetCommands + +function convertToSetCommand(key, value) { + var line = "" + key = key || "" + key = key.trim() + value = value || "" + value = value.trim() + if(key && value && value.length > 0) { + line = "@SET " + key + "=" + replaceDollarWithPercentPair(value) + "\r\n" + } + return line +} + +function extractVariableValuePairs(declarations) { + var pairs = {} + declarations.map(function(declaration) { + var split = declaration.split("=") + pairs[split[0]]=split[1] + }) + return pairs +} + +function convertToSetCommands(variableString) { + var variableValuePairs = extractVariableValuePairs(variableString.split(" ")) + var variableDeclarationsAsBatch = "" + Object.keys(variableValuePairs).forEach(function (key) { + variableDeclarationsAsBatch += convertToSetCommand(key, variableValuePairs[key]) + }) + return variableDeclarationsAsBatch +} + +function replaceDollarWithPercentPair(value) { + var dollarExpressions = /\$\{?([^\$@#\?\- \t{}:]+)\}?/g + var result = "" + var startIndex = 0 + value = value || "" + do { + var match = dollarExpressions.exec(value) + if(match) { + var betweenMatches = value.substring(startIndex, match.index) || "" + result += betweenMatches + "%" + match[1] + "%" + startIndex = dollarExpressions.lastIndex + } + } while (dollarExpressions.lastIndex > 0) + result += value.substr(startIndex) + return result +} + + /***/ }), @@ -17527,158 +17527,158 @@ convert.rgb.gray = function (rgb) { /***/ (function(module, exports, __webpack_require__) { "use strict"; - - -module.exports = { - "aliceblue": [240, 248, 255], - "antiquewhite": [250, 235, 215], - "aqua": [0, 255, 255], - "aquamarine": [127, 255, 212], - "azure": [240, 255, 255], - "beige": [245, 245, 220], - "bisque": [255, 228, 196], - "black": [0, 0, 0], - "blanchedalmond": [255, 235, 205], - "blue": [0, 0, 255], - "blueviolet": [138, 43, 226], - "brown": [165, 42, 42], - "burlywood": [222, 184, 135], - "cadetblue": [95, 158, 160], - "chartreuse": [127, 255, 0], - "chocolate": [210, 105, 30], - "coral": [255, 127, 80], - "cornflowerblue": [100, 149, 237], - "cornsilk": [255, 248, 220], - "crimson": [220, 20, 60], - "cyan": [0, 255, 255], - "darkblue": [0, 0, 139], - "darkcyan": [0, 139, 139], - "darkgoldenrod": [184, 134, 11], - "darkgray": [169, 169, 169], - "darkgreen": [0, 100, 0], - "darkgrey": [169, 169, 169], - "darkkhaki": [189, 183, 107], - "darkmagenta": [139, 0, 139], - "darkolivegreen": [85, 107, 47], - "darkorange": [255, 140, 0], - "darkorchid": [153, 50, 204], - "darkred": [139, 0, 0], - "darksalmon": [233, 150, 122], - "darkseagreen": [143, 188, 143], - "darkslateblue": [72, 61, 139], - "darkslategray": [47, 79, 79], - "darkslategrey": [47, 79, 79], - "darkturquoise": [0, 206, 209], - "darkviolet": [148, 0, 211], - "deeppink": [255, 20, 147], - "deepskyblue": [0, 191, 255], - "dimgray": [105, 105, 105], - "dimgrey": [105, 105, 105], - "dodgerblue": [30, 144, 255], - "firebrick": [178, 34, 34], - "floralwhite": [255, 250, 240], - "forestgreen": [34, 139, 34], - "fuchsia": [255, 0, 255], - "gainsboro": [220, 220, 220], - "ghostwhite": [248, 248, 255], - "gold": [255, 215, 0], - "goldenrod": [218, 165, 32], - "gray": [128, 128, 128], - "green": [0, 128, 0], - "greenyellow": [173, 255, 47], - "grey": [128, 128, 128], - "honeydew": [240, 255, 240], - "hotpink": [255, 105, 180], - "indianred": [205, 92, 92], - "indigo": [75, 0, 130], - "ivory": [255, 255, 240], - "khaki": [240, 230, 140], - "lavender": [230, 230, 250], - "lavenderblush": [255, 240, 245], - "lawngreen": [124, 252, 0], - "lemonchiffon": [255, 250, 205], - "lightblue": [173, 216, 230], - "lightcoral": [240, 128, 128], - "lightcyan": [224, 255, 255], - "lightgoldenrodyellow": [250, 250, 210], - "lightgray": [211, 211, 211], - "lightgreen": [144, 238, 144], - "lightgrey": [211, 211, 211], - "lightpink": [255, 182, 193], - "lightsalmon": [255, 160, 122], - "lightseagreen": [32, 178, 170], - "lightskyblue": [135, 206, 250], - "lightslategray": [119, 136, 153], - "lightslategrey": [119, 136, 153], - "lightsteelblue": [176, 196, 222], - "lightyellow": [255, 255, 224], - "lime": [0, 255, 0], - "limegreen": [50, 205, 50], - "linen": [250, 240, 230], - "magenta": [255, 0, 255], - "maroon": [128, 0, 0], - "mediumaquamarine": [102, 205, 170], - "mediumblue": [0, 0, 205], - "mediumorchid": [186, 85, 211], - "mediumpurple": [147, 112, 219], - "mediumseagreen": [60, 179, 113], - "mediumslateblue": [123, 104, 238], - "mediumspringgreen": [0, 250, 154], - "mediumturquoise": [72, 209, 204], - "mediumvioletred": [199, 21, 133], - "midnightblue": [25, 25, 112], - "mintcream": [245, 255, 250], - "mistyrose": [255, 228, 225], - "moccasin": [255, 228, 181], - "navajowhite": [255, 222, 173], - "navy": [0, 0, 128], - "oldlace": [253, 245, 230], - "olive": [128, 128, 0], - "olivedrab": [107, 142, 35], - "orange": [255, 165, 0], - "orangered": [255, 69, 0], - "orchid": [218, 112, 214], - "palegoldenrod": [238, 232, 170], - "palegreen": [152, 251, 152], - "paleturquoise": [175, 238, 238], - "palevioletred": [219, 112, 147], - "papayawhip": [255, 239, 213], - "peachpuff": [255, 218, 185], - "peru": [205, 133, 63], - "pink": [255, 192, 203], - "plum": [221, 160, 221], - "powderblue": [176, 224, 230], - "purple": [128, 0, 128], - "rebeccapurple": [102, 51, 153], - "red": [255, 0, 0], - "rosybrown": [188, 143, 143], - "royalblue": [65, 105, 225], - "saddlebrown": [139, 69, 19], - "salmon": [250, 128, 114], - "sandybrown": [244, 164, 96], - "seagreen": [46, 139, 87], - "seashell": [255, 245, 238], - "sienna": [160, 82, 45], - "silver": [192, 192, 192], - "skyblue": [135, 206, 235], - "slateblue": [106, 90, 205], - "slategray": [112, 128, 144], - "slategrey": [112, 128, 144], - "snow": [255, 250, 250], - "springgreen": [0, 255, 127], - "steelblue": [70, 130, 180], - "tan": [210, 180, 140], - "teal": [0, 128, 128], - "thistle": [216, 191, 216], - "tomato": [255, 99, 71], - "turquoise": [64, 224, 208], - "violet": [238, 130, 238], - "wheat": [245, 222, 179], - "white": [255, 255, 255], - "whitesmoke": [245, 245, 245], - "yellow": [255, 255, 0], - "yellowgreen": [154, 205, 50] -}; + + +module.exports = { + "aliceblue": [240, 248, 255], + "antiquewhite": [250, 235, 215], + "aqua": [0, 255, 255], + "aquamarine": [127, 255, 212], + "azure": [240, 255, 255], + "beige": [245, 245, 220], + "bisque": [255, 228, 196], + "black": [0, 0, 0], + "blanchedalmond": [255, 235, 205], + "blue": [0, 0, 255], + "blueviolet": [138, 43, 226], + "brown": [165, 42, 42], + "burlywood": [222, 184, 135], + "cadetblue": [95, 158, 160], + "chartreuse": [127, 255, 0], + "chocolate": [210, 105, 30], + "coral": [255, 127, 80], + "cornflowerblue": [100, 149, 237], + "cornsilk": [255, 248, 220], + "crimson": [220, 20, 60], + "cyan": [0, 255, 255], + "darkblue": [0, 0, 139], + "darkcyan": [0, 139, 139], + "darkgoldenrod": [184, 134, 11], + "darkgray": [169, 169, 169], + "darkgreen": [0, 100, 0], + "darkgrey": [169, 169, 169], + "darkkhaki": [189, 183, 107], + "darkmagenta": [139, 0, 139], + "darkolivegreen": [85, 107, 47], + "darkorange": [255, 140, 0], + "darkorchid": [153, 50, 204], + "darkred": [139, 0, 0], + "darksalmon": [233, 150, 122], + "darkseagreen": [143, 188, 143], + "darkslateblue": [72, 61, 139], + "darkslategray": [47, 79, 79], + "darkslategrey": [47, 79, 79], + "darkturquoise": [0, 206, 209], + "darkviolet": [148, 0, 211], + "deeppink": [255, 20, 147], + "deepskyblue": [0, 191, 255], + "dimgray": [105, 105, 105], + "dimgrey": [105, 105, 105], + "dodgerblue": [30, 144, 255], + "firebrick": [178, 34, 34], + "floralwhite": [255, 250, 240], + "forestgreen": [34, 139, 34], + "fuchsia": [255, 0, 255], + "gainsboro": [220, 220, 220], + "ghostwhite": [248, 248, 255], + "gold": [255, 215, 0], + "goldenrod": [218, 165, 32], + "gray": [128, 128, 128], + "green": [0, 128, 0], + "greenyellow": [173, 255, 47], + "grey": [128, 128, 128], + "honeydew": [240, 255, 240], + "hotpink": [255, 105, 180], + "indianred": [205, 92, 92], + "indigo": [75, 0, 130], + "ivory": [255, 255, 240], + "khaki": [240, 230, 140], + "lavender": [230, 230, 250], + "lavenderblush": [255, 240, 245], + "lawngreen": [124, 252, 0], + "lemonchiffon": [255, 250, 205], + "lightblue": [173, 216, 230], + "lightcoral": [240, 128, 128], + "lightcyan": [224, 255, 255], + "lightgoldenrodyellow": [250, 250, 210], + "lightgray": [211, 211, 211], + "lightgreen": [144, 238, 144], + "lightgrey": [211, 211, 211], + "lightpink": [255, 182, 193], + "lightsalmon": [255, 160, 122], + "lightseagreen": [32, 178, 170], + "lightskyblue": [135, 206, 250], + "lightslategray": [119, 136, 153], + "lightslategrey": [119, 136, 153], + "lightsteelblue": [176, 196, 222], + "lightyellow": [255, 255, 224], + "lime": [0, 255, 0], + "limegreen": [50, 205, 50], + "linen": [250, 240, 230], + "magenta": [255, 0, 255], + "maroon": [128, 0, 0], + "mediumaquamarine": [102, 205, 170], + "mediumblue": [0, 0, 205], + "mediumorchid": [186, 85, 211], + "mediumpurple": [147, 112, 219], + "mediumseagreen": [60, 179, 113], + "mediumslateblue": [123, 104, 238], + "mediumspringgreen": [0, 250, 154], + "mediumturquoise": [72, 209, 204], + "mediumvioletred": [199, 21, 133], + "midnightblue": [25, 25, 112], + "mintcream": [245, 255, 250], + "mistyrose": [255, 228, 225], + "moccasin": [255, 228, 181], + "navajowhite": [255, 222, 173], + "navy": [0, 0, 128], + "oldlace": [253, 245, 230], + "olive": [128, 128, 0], + "olivedrab": [107, 142, 35], + "orange": [255, 165, 0], + "orangered": [255, 69, 0], + "orchid": [218, 112, 214], + "palegoldenrod": [238, 232, 170], + "palegreen": [152, 251, 152], + "paleturquoise": [175, 238, 238], + "palevioletred": [219, 112, 147], + "papayawhip": [255, 239, 213], + "peachpuff": [255, 218, 185], + "peru": [205, 133, 63], + "pink": [255, 192, 203], + "plum": [221, 160, 221], + "powderblue": [176, 224, 230], + "purple": [128, 0, 128], + "rebeccapurple": [102, 51, 153], + "red": [255, 0, 0], + "rosybrown": [188, 143, 143], + "royalblue": [65, 105, 225], + "saddlebrown": [139, 69, 19], + "salmon": [250, 128, 114], + "sandybrown": [244, 164, 96], + "seagreen": [46, 139, 87], + "seashell": [255, 245, 238], + "sienna": [160, 82, 45], + "silver": [192, 192, 192], + "skyblue": [135, 206, 235], + "slateblue": [106, 90, 205], + "slategray": [112, 128, 144], + "slategrey": [112, 128, 144], + "snow": [255, 250, 250], + "springgreen": [0, 255, 127], + "steelblue": [70, 130, 180], + "tan": [210, 180, 140], + "teal": [0, 128, 128], + "thistle": [216, 191, 216], + "tomato": [255, 99, 71], + "turquoise": [64, 224, 208], + "violet": [238, 130, 238], + "wheat": [245, 222, 179], + "white": [255, 255, 255], + "whitesmoke": [245, 245, 245], + "yellow": [255, 255, 0], + "yellowgreen": [154, 205, 50] +}; /***/ }), @@ -26026,7 +26026,7 @@ const YARN_EXEC = process.env.npm_execpath || 'yarn'; * Install all dependencies in the given directory */ async function installInDir(directory, extraArgs = [], useAdd = false) { - const options = [useAdd ? 'add' : 'install', '--non-interactive', ...extraArgs]; + const options = [useAdd ? 'add' : 'install', '--non-interactive', '--ignore-engines', ...extraArgs]; // We pass the mutex flag to ensure only one instance of yarn runs at any // given time (e.g. to avoid conflicts). diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap index 95e501650f08..7f896674faac 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav_group_enabled.test.tsx.snap @@ -236,7 +236,7 @@ exports[` should render correctly 1`] = ` class="euiHorizontalRule euiHorizontalRule--full" />
@@ -260,7 +260,7 @@ exports[` should render correctly 2`] = ` class="euiHorizontalRule euiHorizontalRule--full" />
@@ -333,7 +333,7 @@ exports[` should show all use case by default and class="euiHorizontalRule euiHorizontalRule--full" />
@@ -406,7 +406,7 @@ exports[` should show all use case when current na class="euiHorizontalRule euiHorizontalRule--full" />
diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss index 39978cc2eff6..978ed743a24b 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.scss @@ -62,6 +62,7 @@ .bottom-container { padding: 0 $euiSize; display: flex; + -ms-overflow-style: -ms-autohiding-scrollbar; &.bottom-container-collapsed { flex-direction: column; diff --git a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx index af67974ecb9d..d196e760e43b 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav_group_enabled.tsx @@ -435,6 +435,7 @@ export function CollapsibleNavGroupEnabled({
', () => { + it('should call chrome.navGroup.setCurrentNavGroup and application.navigateToApp methods from core service when click', () => { + const coreStartMock = coreMock.createStart(); + const { container } = render(); + const component = container.children[0]; + fireEvent.click(component); + expect(coreStartMock.application.navigateToApp).toBeCalledWith('foo'); + }); +}); diff --git a/src/plugins/home/public/application/components/home_icon.tsx b/src/plugins/home/public/application/components/home_icon.tsx new file mode 100644 index 000000000000..705b89df9bab --- /dev/null +++ b/src/plugins/home/public/application/components/home_icon.tsx @@ -0,0 +1,20 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { EuiButtonIcon } from '@elastic/eui'; +import { CoreStart } from 'opensearch-dashboards/public'; + +export function HomeIcon({ core, appId }: { core: CoreStart; appId: string }) { + return ( + { + core.application.navigateToApp(appId); + }} + /> + ); +} diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index fe1099a8e635..cf499c19ddb9 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -37,6 +37,7 @@ import { } from 'opensearch-dashboards/public'; import { i18n } from '@osd/i18n'; import { first } from 'rxjs/operators'; +import React from 'react'; import { Branding } from 'src/core/types'; import { @@ -70,6 +71,8 @@ import { ContentManagementPluginStart, } from '../../content_management/public'; import { initHome, setupHome } from './application/home_render'; +import { toMountPoint } from '../../opensearch_dashboards_react/public'; +import { HomeIcon } from './application/components/home_icon'; export interface HomePluginStartDependencies { data: DataPublicPluginStart; @@ -151,9 +154,7 @@ export class HomePublicPlugin core.application.register({ id: PLUGIN_ID, title: 'Home', - navLinkStatus: core.chrome.navGroup.getNavGroupEnabled() - ? undefined - : AppNavLinkStatus.hidden, + navLinkStatus: AppNavLinkStatus.hidden, mount: async (params: AppMountParameters) => { const [coreStart] = await core.getStartServices(); setCommonService(); @@ -166,13 +167,6 @@ export class HomePublicPlugin workspaceAvailability: WorkspaceAvailability.outsideWorkspace, }); - core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ - { - id: PLUGIN_ID, - title: 'Home', - }, - ]); - // Register import sample data as a standalone app so that it is available inside workspace. core.application.register({ id: IMPORT_SAMPLE_DATA_APP_ID, @@ -255,6 +249,18 @@ export class HomePublicPlugin }); } + if (core.chrome.navGroup.getNavGroupEnabled()) { + core.chrome.navControls.registerLeftBottom({ + order: 0, + mount: toMountPoint( + React.createElement(HomeIcon, { + core, + appId: PLUGIN_ID, + }) + ), + }); + } + return { featureCatalogue: this.featuresCatalogueRegistry, getSavedHomepageLoader: () => this.sectionTypeService.getSavedHomepageLoader(), diff --git a/src/plugins/saved_objects_management/public/plugin.ts b/src/plugins/saved_objects_management/public/plugin.ts index 2f69c1587c65..104507f028e2 100644 --- a/src/plugins/saved_objects_management/public/plugin.ts +++ b/src/plugins/saved_objects_management/public/plugin.ts @@ -198,7 +198,7 @@ export class SavedObjectsManagementPlugin core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [ { id: APP_ID, - order: 300, + order: 400, }, ]); diff --git a/src/plugins/visualize/public/plugin.ts b/src/plugins/visualize/public/plugin.ts index 311fc20ed85d..835bfb306796 100644 --- a/src/plugins/visualize/public/plugin.ts +++ b/src/plugins/visualize/public/plugin.ts @@ -228,11 +228,16 @@ export class VisualizePlugin }, }); + const titleInLeftNav = i18n.translate('visualize.leftNav.visualizeTitle', { + defaultMessage: 'Visualizations', + }); + core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.observability, [ { id: visualizeAppId, category: DEFAULT_APP_CATEGORIES.visualizeAndReport, order: 200, + title: titleInLeftNav, }, ]); core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS['security-analytics'], [ @@ -240,13 +245,15 @@ export class VisualizePlugin id: visualizeAppId, category: DEFAULT_APP_CATEGORIES.visualizeAndReport, order: 200, + title: titleInLeftNav, }, ]); core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.essentials, [ { id: visualizeAppId, - category: DEFAULT_APP_CATEGORIES.visualizeAndReport, - order: 200, + category: undefined, + order: 400, + title: titleInLeftNav, }, ]); core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.search, [ @@ -254,6 +261,7 @@ export class VisualizePlugin id: visualizeAppId, category: DEFAULT_APP_CATEGORIES.analyzeSearch, order: 400, + title: titleInLeftNav, }, ]); core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ @@ -261,6 +269,7 @@ export class VisualizePlugin id: visualizeAppId, category: undefined, order: 400, + title: titleInLeftNav, }, ]); diff --git a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx index f0a5f6f7fc8e..0e27580300bc 100644 --- a/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx +++ b/src/plugins/workspace/public/components/workspace_menu/workspace_menu.tsx @@ -17,7 +17,6 @@ import { EuiFlexItem, EuiFlexGroup, EuiListGroup, - EuiButtonIcon, EuiButtonEmpty, EuiSmallButton, EuiSmallButtonIcon, @@ -111,7 +110,11 @@ export const WorkspaceMenu = ({ coreStart, registeredUseCases$ }: Props) => { }; const currentWorkspaceButton = currentWorkspace ? ( - + { expect.arrayContaining([ { id: 'workspace_list', - order: 150, - title: 'Workspace settings', + order: 350, + title: 'Workspaces', }, ]) ); }); - it('#setup should register workspace detail with a visible application and register to all nav group', async () => { + it('#setup should register workspace detail', async () => { const setupMock = coreMock.createSetup(); setupMock.chrome.navGroup.getNavGroupEnabled.mockReturnValue(true); const workspacePlugin = new WorkspacePlugin(); @@ -189,20 +189,8 @@ describe('Workspace plugin', () => { expect(setupMock.application.register).toHaveBeenCalledWith( expect.objectContaining({ id: 'workspace_detail', - navLinkStatus: AppNavLinkStatus.hidden, }) ); - - expect(setupMock.chrome.navGroup.addNavLinksToGroup).toHaveBeenCalledWith( - DEFAULT_NAV_GROUPS.all, - expect.arrayContaining([ - { - id: 'workspace_detail', - title: 'Overview', - order: 100, - }, - ]) - ); }); it('#setup should register workspace initial with a visible application', async () => { diff --git a/src/plugins/workspace/public/plugin.ts b/src/plugins/workspace/public/plugin.ts index 4731e9d205b7..1617744fa9ff 100644 --- a/src/plugins/workspace/public/plugin.ts +++ b/src/plugins/workspace/public/plugin.ts @@ -113,19 +113,7 @@ export class WorkspacePlugin this.registeredUseCases$, ]).subscribe(([currentWorkspace, registeredUseCases]) => { if (currentWorkspace) { - const isAllUseCase = - getFirstUseCaseOfFeatureConfigs(currentWorkspace.features || []) === ALL_USE_CASE_ID; this.appUpdater$.next((app) => { - // When in all workspace, the home should be replaced by workspace detail page - if (app.id === 'home' && isAllUseCase) { - return { navLinkStatus: AppNavLinkStatus.hidden }; - } - - // show the overview page in all use case - if (app.id === WORKSPACE_DETAIL_APP_ID && isAllUseCase) { - return { navLinkStatus: AppNavLinkStatus.visible }; - } - if (isAppAccessibleInWorkspace(app, currentWorkspace, registeredUseCases)) { return; } @@ -356,7 +344,6 @@ export class WorkspacePlugin title: i18n.translate('workspace.settings.workspaceDetail', { defaultMessage: 'Workspace Detail', }), - navLinkStatus: AppNavLinkStatus.hidden, async mount(params: AppMountParameters) { const { renderDetailApp } = await import('./application'); return mountWorkspaceApp(params, renderDetailApp); @@ -425,16 +412,6 @@ export class WorkspacePlugin workspaceAvailability: WorkspaceAvailability.outsideWorkspace, }); - core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.all, [ - { - id: WORKSPACE_DETAIL_APP_ID, - order: 100, - title: i18n.translate('workspace.nav.workspaceDetail.title', { - defaultMessage: 'Overview', - }), - }, - ]); - /** * register workspace column into saved objects table */ @@ -446,9 +423,9 @@ export class WorkspacePlugin core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.settingsAndSetup, [ { id: WORKSPACE_LIST_APP_ID, - order: 150, - title: i18n.translate('workspace.settings.workspaceSettings', { - defaultMessage: 'Workspace settings', + order: 350, + title: i18n.translate('workspace.settings.workspaces', { + defaultMessage: 'Workspaces', }), }, ]); diff --git a/src/plugins/workspace/public/services/use_case_service.test.ts b/src/plugins/workspace/public/services/use_case_service.test.ts index 00938fd7d60d..203cb48fe842 100644 --- a/src/plugins/workspace/public/services/use_case_service.test.ts +++ b/src/plugins/workspace/public/services/use_case_service.test.ts @@ -5,14 +5,17 @@ import { BehaviorSubject } from 'rxjs'; import { first } from 'rxjs/operators'; -import { chromeServiceMock } from '../../../../core/public/mocks'; +import { chromeServiceMock, coreMock } from '../../../../core/public/mocks'; import { ALL_USE_CASE_ID, + DEFAULT_APP_CATEGORIES, DEFAULT_NAV_GROUPS, NavGroupItemInMap, NavGroupType, } from '../../../../core/public'; import { UseCaseService } from './use_case_service'; +import { waitFor } from '@testing-library/dom'; +import { WORKSPACE_DETAIL_APP_ID } from '../../common/constants'; const mockNavGroupsMap = { system: { @@ -61,6 +64,54 @@ const setupUseCaseStart = (options?: { navGroupEnabled?: boolean }) => { }; describe('UseCaseService', () => { + describe('#setup', () => { + it('should add manage workspace category to current use case', async () => { + const useCaseService = new UseCaseService(); + const coreSetup = coreMock.createSetup(); + const navGroupMap$ = new BehaviorSubject>({}); + const coreStartMock = coreMock.createStart(); + coreSetup.getStartServices.mockResolvedValue([coreStartMock, {}, {}]); + coreStartMock.chrome.navGroup.getNavGroupsMap$.mockReturnValue(navGroupMap$); + useCaseService.setup(coreSetup); + const navGroupInfo = { + ...DEFAULT_NAV_GROUPS.all, + navLinks: [], + }; + navGroupMap$.next({ + [ALL_USE_CASE_ID]: navGroupInfo, + }); + coreSetup.workspaces.currentWorkspace$.next({ + id: ALL_USE_CASE_ID, + name: ALL_USE_CASE_ID, + features: [`use-case-${ALL_USE_CASE_ID}`], + }); + await waitFor(() => { + expect(coreSetup.chrome.navGroup.addNavLinksToGroup).toBeCalledWith(navGroupInfo, [ + { + id: 'dataSources', + category: DEFAULT_APP_CATEGORIES.manageWorkspace, + order: 100, + }, + { + id: 'indexPatterns', + category: DEFAULT_APP_CATEGORIES.manageWorkspace, + order: 200, + }, + { + id: 'objects', + category: DEFAULT_APP_CATEGORIES.manageWorkspace, + order: 300, + }, + { + id: WORKSPACE_DETAIL_APP_ID, + category: DEFAULT_APP_CATEGORIES.manageWorkspace, + order: 400, + title: 'Workspace settings', + }, + ]); + }); + }); + }); describe('#start', () => { it('should return built in use cases when nav group disabled', async () => { const { useCaseStart } = setupUseCaseStart({ diff --git a/src/plugins/workspace/public/services/use_case_service.ts b/src/plugins/workspace/public/services/use_case_service.ts index 681cf141327a..630ba9f15e29 100644 --- a/src/plugins/workspace/public/services/use_case_service.ts +++ b/src/plugins/workspace/public/services/use_case_service.ts @@ -5,6 +5,7 @@ import { combineLatest, Observable, Subscription } from 'rxjs'; import { distinctUntilChanged, map } from 'rxjs/operators'; +import { i18n } from '@osd/i18n'; import { ChromeStart, @@ -15,7 +16,7 @@ import { DEFAULT_NAV_GROUPS, ALL_USE_CASE_ID, } from '../../../../core/public'; -import { WORKSPACE_USE_CASES } from '../../common/constants'; +import { WORKSPACE_DETAIL_APP_ID, WORKSPACE_USE_CASES } from '../../common/constants'; import { convertNavGroupToWorkspaceUseCase, getFirstUseCaseOfFeatureConfigs, @@ -78,6 +79,14 @@ export class UseCaseService { category: DEFAULT_APP_CATEGORIES.manageWorkspace, order: 300, }, + { + id: WORKSPACE_DETAIL_APP_ID, + category: DEFAULT_APP_CATEGORIES.manageWorkspace, + order: 400, + title: i18n.translate('workspace.settings.workspaceSettings', { + defaultMessage: 'Workspace settings', + }), + }, ]); } }); From e6ea7192e2a50ac710bab15f83f24d020e746ef9 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:27:34 +0800 Subject: [PATCH 243/276] [Workspace]Remove default appended features (#7841) (#7846) * Remove workspace_detail from default append features * Changeset file for PR #7841 created/updated --------- (cherry picked from commit ca66127a09116de4b552b09635a14eee82f97649) Signed-off-by: Lin Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7841.yml | 2 ++ src/plugins/workspace/common/constants.ts | 5 ----- .../workspace_form/use_workspace_form.test.ts | 2 +- .../components/workspace_form/use_workspace_form.ts | 7 ++----- .../public/components/workspace_form/utils.ts | 11 +---------- src/plugins/workspace/public/utils.ts | 3 +-- 6 files changed, 7 insertions(+), 23 deletions(-) create mode 100644 changelogs/fragments/7841.yml diff --git a/changelogs/fragments/7841.yml b/changelogs/fragments/7841.yml new file mode 100644 index 000000000000..06fc241b193d --- /dev/null +++ b/changelogs/fragments/7841.yml @@ -0,0 +1,2 @@ +feat: +- [Workspace]Remove default appended features ([#7841](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7841)) \ No newline at end of file diff --git a/src/plugins/workspace/common/constants.ts b/src/plugins/workspace/common/constants.ts index 88f9a5dd9ff4..7cabf32d14c6 100644 --- a/src/plugins/workspace/common/constants.ts +++ b/src/plugins/workspace/common/constants.ts @@ -13,11 +13,6 @@ export const WORKSPACE_DETAIL_APP_ID = 'workspace_detail'; export const WORKSPACE_INITIAL_APP_ID = 'workspace_initial'; export const WORKSPACE_NAVIGATION_APP_ID = 'workspace_navigation'; -/** - * Since every workspace always have overview and update page, these features will be selected by default - * and can't be changed in the workspace form feature selector - */ -export const DEFAULT_SELECTED_FEATURES_IDS = [WORKSPACE_DETAIL_APP_ID]; export const WORKSPACE_SAVED_OBJECTS_CLIENT_WRAPPER_ID = 'workspace'; export const WORKSPACE_CONFLICT_CONTROL_SAVED_OBJECTS_CLIENT_WRAPPER_ID = 'workspace_conflict_control'; diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts index c946cb35a68c..6e25c81d4440 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.test.ts @@ -123,7 +123,7 @@ describe('useWorkspaceForm', () => { expect(onSubmitMock).toHaveBeenCalledWith( expect.objectContaining({ name: 'test-workspace-name', - features: ['use-case-observability', 'workspace_detail'], + features: ['use-case-observability'], }) ); }); diff --git a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts index fb8bf40e497c..f627df1f3aad 100644 --- a/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts +++ b/src/plugins/workspace/public/components/workspace_form/use_workspace_form.ts @@ -15,7 +15,6 @@ import { import { DataSource } from '../../../common/types'; import { WorkspaceFormProps, WorkspaceFormErrors, WorkspacePermissionSetting } from './types'; import { - appendDefaultFeatureIds, generatePermissionSettingsState, getNumberOfChanges, getNumberOfErrors, @@ -42,9 +41,7 @@ export const useWorkspaceForm = ({ generatePermissionSettingsState(operationType, defaultValues?.permissionSettings) ); - const [featureConfigs, setFeatureConfigs] = useState( - appendDefaultFeatureIds(defaultValues?.features ?? []) - ); + const [featureConfigs, setFeatureConfigs] = useState(defaultValues?.features ?? []); const selectedUseCase = useMemo(() => getFirstUseCaseOfFeatureConfigs(featureConfigs), [ featureConfigs, ]); @@ -138,7 +135,7 @@ export const useWorkspaceForm = ({ setName(resetValues?.name ?? ''); setDescription(resetValues?.description ?? ''); setColor(resetValues?.color); - setFeatureConfigs(appendDefaultFeatureIds(resetValues?.features ?? [])); + setFeatureConfigs(resetValues?.features ?? []); setPermissionSettings(initialPermissionSettingsRef.current); setFormErrors({}); setIsEditing(false); diff --git a/src/plugins/workspace/public/components/workspace_form/utils.ts b/src/plugins/workspace/public/components/workspace_form/utils.ts index a1a340a78db6..04c1f3772600 100644 --- a/src/plugins/workspace/public/components/workspace_form/utils.ts +++ b/src/plugins/workspace/public/components/workspace_form/utils.ts @@ -6,11 +6,7 @@ import { i18n } from '@osd/i18n'; import type { SavedObjectPermissions } from '../../../../../core/types'; -import { - CURRENT_USER_PLACEHOLDER, - DEFAULT_SELECTED_FEATURES_IDS, - WorkspacePermissionMode, -} from '../../../common/constants'; +import { CURRENT_USER_PLACEHOLDER, WorkspacePermissionMode } from '../../../common/constants'; import { isUseCaseFeatureConfig } from '../../utils'; import { optionIdToWorkspacePermissionModesMap, @@ -32,11 +28,6 @@ import { import { DataSource } from '../../../common/types'; import { validateWorkspaceColor } from '../../../common/utils'; -export const appendDefaultFeatureIds = (ids: string[]) => { - // concat default checked ids and unique the result - return Array.from(new Set(ids.concat(DEFAULT_SELECTED_FEATURES_IDS))); -}; - export const isValidFormTextInput = (input?: string) => { /** * This regular expression is from the workspace form name and description field UI. diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index bbadd528d73d..ff3983e415d4 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -23,7 +23,7 @@ import { WorkspaceObject, WorkspaceAvailability, } from '../../../core/public'; -import { DEFAULT_SELECTED_FEATURES_IDS, WORKSPACE_DETAIL_APP_ID } from '../common/constants'; +import { WORKSPACE_DETAIL_APP_ID } from '../common/constants'; import { WorkspaceUseCase, WorkspaceUseCaseFeature } from './types'; import { formatUrlWithWorkspaceId } from '../../../core/public/utils'; import { SigV4ServiceName } from '../../../plugins/data_source/common/data_sources'; @@ -188,7 +188,6 @@ export const filterWorkspaceConfigurableApps = (applications: PublicAppInfo[]) = const filterCondition = navLinkStatus !== AppNavLinkStatus.hidden && !chromeless && - !DEFAULT_SELECTED_FEATURES_IDS.includes(id) && workspaceAvailability !== WorkspaceAvailability.outsideWorkspace; // If the category is management, only retain Dashboards Management which contains saved objets and index patterns. // Saved objets can show all saved objects in the current workspace and index patterns is at workspace level. From 05758b3f47e746fa25a44835c18bb0b462a809bf Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:27:51 +0800 Subject: [PATCH 244/276] [Workspace] feat: add data source and owners column to workspace list page table (#7818) (#7856) * init new workspace list column * feat: addo owners and data source column to table * test: update snapshots * test: add test cases * test: update utils test --------- (cherry picked from commit 04fca308ff8c3efea864eefbb8b3014a3e72c870) Signed-off-by: tygao Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- src/core/public/index.ts | 1 + .../saved_objects/simple_saved_object.ts | 3 + .../__snapshots__/index.test.tsx.snap | 181 ++++++++++++++++-- .../components/workspace_list/index.test.tsx | 57 +++++- .../components/workspace_list/index.tsx | 109 +++++++++-- src/plugins/workspace/public/types.ts | 5 + src/plugins/workspace/public/utils.test.ts | 1 + src/plugins/workspace/public/utils.ts | 9 +- 8 files changed, 328 insertions(+), 38 deletions(-) diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 979e618fb505..a97f948a9d67 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -126,6 +126,7 @@ export { ChromeNavGroup, NavGroupType, NavGroupStatus, + WorkspaceAttributeWithPermission, } from '../types'; export { diff --git a/src/core/public/saved_objects/simple_saved_object.ts b/src/core/public/saved_objects/simple_saved_object.ts index 71b1445e95aa..cd53f2b4123a 100644 --- a/src/core/public/saved_objects/simple_saved_object.ts +++ b/src/core/public/saved_objects/simple_saved_object.ts @@ -52,6 +52,7 @@ export class SimpleSavedObject { public error: SavedObjectType['error']; public references: SavedObjectType['references']; public updated_at: SavedObjectType['updated_at']; + public workspaces: SavedObjectType['workspaces']; constructor( private client: SavedObjectsClientContract, @@ -64,6 +65,7 @@ export class SimpleSavedObject { references, migrationVersion, updated_at: updateAt, + workspaces, }: SavedObjectType ) { this.id = id; @@ -73,6 +75,7 @@ export class SimpleSavedObject { this._version = version; this.migrationVersion = migrationVersion; this.updated_at = updateAt; + this.workspaces = workspaces; if (error) { this.error = error; } diff --git a/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap b/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap index 3ead301fd7c2..0649f595b643 100644 --- a/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap +++ b/src/plugins/workspace/public/components/workspace_list/__snapshots__/index.test.tsx.snap @@ -222,7 +222,7 @@ exports[`WorkspaceList should render title and table normally 1`] = ` data-test-subj="tableHeaderCell_name_0" role="columnheader" scope="col" - style="width: 25%;" + style="width: 15%;" >
+ + + Owners + + + + + + Data sources + + +
+
+ Owners +
+
+ admin +   + + + + + + +
+
+
+ Data sources +
+
+
@@ -498,7 +593,7 @@ exports[`WorkspaceList should render title and table normally 1`] = `
+
+ Owners +
+
+
+
+ Data sources +
+
+
@@ -650,7 +771,7 @@ exports[`WorkspaceList should render title and table normally 1`] = `
+
+ Owners +
+
+
+
+ Data sources +
+
+
diff --git a/src/plugins/workspace/public/components/workspace_list/index.test.tsx b/src/plugins/workspace/public/components/workspace_list/index.test.tsx index 54123acceb9f..bec37c5bb160 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.test.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import moment from 'moment'; import { of } from 'rxjs'; -import { render, fireEvent, screen } from '@testing-library/react'; +import { render, fireEvent, screen, waitFor } from '@testing-library/react'; import { I18nProvider } from '@osd/i18n/react'; import { coreMock } from '../../../../../core/public/mocks'; import { navigateToWorkspaceDetail } from '../utils/workspace'; @@ -36,6 +36,30 @@ jest.mock('../delete_workspace_modal', () => ({ ), })); +jest.mock('../../utils', () => { + const original = jest.requireActual('../../utils'); + return { + ...original, + getDataSourcesList: jest.fn().mockResolvedValue(() => [ + { + id: 'ds_id1', + title: 'ds_title1', + workspaces: 'id1', + }, + { + id: 'ds_id2', + title: 'ds_title2', + workspaces: 'id1', + }, + { + id: 'ds_id3', + title: 'ds_title3', + workspaces: 'id1', + }, + ]), + }; +}); + function getWrapWorkspaceListInContext( workspaceList = [ { @@ -45,6 +69,11 @@ function getWrapWorkspaceListInContext( description: 'should be able to see the description tooltip when hovering over the description', lastUpdatedTime: '1999-08-06T02:00:00.00Z', + permissions: { + write: { + users: ['admin', 'nonadmin'], + }, + }, }, { id: 'id2', @@ -104,6 +133,10 @@ function getWrapWorkspaceListInContext( } describe('WorkspaceList', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + it('should render title and table normally', () => { const { getByText, getByRole, container } = render(getWrapWorkspaceListInContext()); expect( @@ -268,4 +301,26 @@ describe('WorkspaceList', () => { const { queryByText } = render(getWrapWorkspaceListInContext([], false)); expect(queryByText('Create workspace')).toBeNull(); }); + + it('should render data source badge when more than two data sources', async () => { + const { getByTestId } = render(getWrapWorkspaceListInContext()); + expect(navigateToWorkspaceDetail).not.toHaveBeenCalled(); + await waitFor(() => { + const badge = getByTestId('workspaceList-more-dataSources-badge'); + expect(badge).toBeInTheDocument(); + fireEvent.click(badge); + }); + expect(navigateToWorkspaceDetail).toHaveBeenCalledTimes(1); + }); + + it('should render owners badge when more than one owners', async () => { + const { getByTestId } = render(getWrapWorkspaceListInContext()); + expect(navigateToWorkspaceDetail).not.toHaveBeenCalled(); + await waitFor(() => { + const badge = getByTestId('workspaceList-more-collaborators-badge'); + expect(badge).toBeInTheDocument(); + fireEvent.click(badge); + }); + expect(navigateToWorkspaceDetail).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/plugins/workspace/public/components/workspace_list/index.tsx b/src/plugins/workspace/public/components/workspace_list/index.tsx index 91fa716890bc..ab38ce7e6a88 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { useState, useMemo, useCallback } from 'react'; +import React, { useState, useMemo, useCallback, useEffect } from 'react'; import moment from 'moment'; import { EuiPage, @@ -19,27 +19,36 @@ import { EuiButtonEmpty, EuiButton, EuiEmptyPrompt, + EuiBadge, } from '@elastic/eui'; import useObservable from 'react-use/lib/useObservable'; import { BehaviorSubject, of } from 'rxjs'; import { i18n } from '@osd/i18n'; -import { DEFAULT_NAV_GROUPS, WorkspaceAttribute } from '../../../../../core/public'; +import { + DEFAULT_NAV_GROUPS, + WorkspaceAttribute, + WorkspaceAttributeWithPermission, +} from '../../../../../core/public'; import { useOpenSearchDashboards } from '../../../../../plugins/opensearch_dashboards_react/public'; import { navigateToWorkspaceDetail } from '../utils/workspace'; +import { DetailTab } from '../workspace_form/constants'; import { WORKSPACE_CREATE_APP_ID } from '../../../common/constants'; import { DeleteWorkspaceModal } from '../delete_workspace_modal'; -import { getFirstUseCaseOfFeatureConfigs } from '../../utils'; +import { getFirstUseCaseOfFeatureConfigs, getDataSourcesList } from '../../utils'; import { WorkspaceUseCase } from '../../types'; import { NavigationPublicPluginStart } from '../../../../../plugins/navigation/public'; +import { WorkspacePermissionMode } from '../../../common/constants'; +import { DataSourceAttributesWithWorkspaces } from '../../types'; export interface WorkspaceListProps { registeredUseCases$: BehaviorSubject; } -interface WorkspaceAttributeWithUseCaseID extends WorkspaceAttribute { +interface WorkspaceAttributeWithUseCaseIDAndDataSources extends WorkspaceAttribute { useCase?: string; + dataSources?: string[]; } export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { @@ -50,6 +59,7 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { http, navigationUI: { HeaderControl }, uiSettings, + savedObjects, }, } = useOpenSearchDashboards<{ navigationUI: NavigationPublicPluginStart['ui']; @@ -67,6 +77,7 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { }); const [deletedWorkspaces, setDeletedWorkspaces] = useState([]); const [selection, setSelection] = useState([]); + const [allDataSources, setAllDataSources] = useState([]); const dateFormat = uiSettings?.get('dateFormat'); @@ -87,14 +98,28 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { [registeredUseCases] ); - const newWorkspaceList: WorkspaceAttributeWithUseCaseID[] = useMemo(() => { + useEffect(() => { + if (savedObjects) { + getDataSourcesList(savedObjects.client, ['*']).then((data) => { + setAllDataSources(data); + }); + } + }, [savedObjects]); + + const newWorkspaceList: WorkspaceAttributeWithUseCaseIDAndDataSources[] = useMemo(() => { return workspaceList.map( - (workspace): WorkspaceAttributeWithUseCaseID => ({ - ...workspace, - useCase: extractUseCaseFromFeatures(workspace.features ?? []), - }) + (workspace): WorkspaceAttributeWithUseCaseIDAndDataSources => { + const associatedDataSourcesTitles = allDataSources + .filter((ds) => ds.workspaces && ds.workspaces.includes(workspace.id)) + .map((ds) => ds.title as string); + return { + ...workspace, + useCase: extractUseCaseFromFeatures(workspace.features ?? []), + dataSources: associatedDataSourcesTitles, + }; + } ); - }, [workspaceList, extractUseCaseFromFeatures]); + }, [workspaceList, extractUseCaseFromFeatures, allDataSources]); const workspaceCreateUrl = useMemo(() => { if (!application) { return ''; @@ -166,14 +191,43 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { }; const handleSwitchWorkspace = useCallback( - (id: string) => { + (id: string, tab?: DetailTab) => { if (application && http) { - navigateToWorkspaceDetail({ application, http }, id); + navigateToWorkspaceDetail({ application, http }, id, tab); } }, [application, http] ); + const renderDataWithMoreBadge = ( + data: string[], + maxDisplayedAmount: number, + workspaceId: string, + tab: DetailTab + ) => { + const amount = data.length; + const mostDisplayedTitles = data.slice(0, maxDisplayedAmount).join(','); + return amount <= maxDisplayedAmount ? ( + mostDisplayedTitles + ) : ( + <> + {mostDisplayedTitles}  + handleSwitchWorkspace(workspaceId, tab)} + iconOnClick={() => handleSwitchWorkspace(workspaceId, tab)} + iconOnClickAriaLabel="Open workspace detail" + onClickAriaLabel="Open workspace detail" + data-test-subj={`workspaceList-more-${tab}-badge`} + > + + {amount - maxDisplayedAmount} more + + + ); + }; + const renderToolsLeft = () => { if (selection.length === 0) { return; @@ -245,9 +299,9 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { { field: 'name', name: 'Name', - width: '25%', + width: '15%', sortable: true, - render: (name: string, item: WorkspaceAttribute) => ( + render: (name: string, item: WorkspaceAttributeWithPermission) => ( handleSwitchWorkspace(item.id)}> {name} @@ -259,13 +313,13 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { { field: 'useCase', name: 'Use case', - width: '20%', + width: '15%', }, { field: 'description', name: 'Description', - width: '20%', + width: '15%', render: (description: string) => ( { ), }, + { + field: 'permissions', + name: 'Owners', + width: '15%', + render: ( + permissions: WorkspaceAttributeWithPermission['permissions'], + item: WorkspaceAttributeWithPermission + ) => { + const owners = permissions?.[WorkspacePermissionMode.Write]?.users ?? []; + return renderDataWithMoreBadge(owners, 1, item.id, DetailTab.Collaborators); + }, + }, { field: 'lastUpdatedTime', name: 'Last updated', - width: '25%', + width: '15%', truncateText: false, render: (lastUpdatedTime: string) => { return moment(lastUpdatedTime).format(dateFormat); }, }, - + { + field: 'dataSources', + width: '15%', + name: 'Data sources', + render: (dataSources: string[], item: WorkspaceAttributeWithPermission) => { + return renderDataWithMoreBadge(dataSources, 2, item.id, DetailTab.DataSources); + }, + }, { name: 'Actions', field: '', diff --git a/src/plugins/workspace/public/types.ts b/src/plugins/workspace/public/types.ts index 8e5076a6cca7..6d47262bbdd9 100644 --- a/src/plugins/workspace/public/types.ts +++ b/src/plugins/workspace/public/types.ts @@ -7,6 +7,7 @@ import { CoreStart } from '../../../core/public'; import { WorkspaceClient } from './workspace_client'; import { DataSourceManagementPluginSetup } from '../../../plugins/data_source_management/public'; import { NavigationPublicPluginStart } from '../../../plugins/navigation/public'; +import { DataSourceAttributes } from '../../../plugins/data_source/common/data_sources'; export type Services = CoreStart & { workspaceClient: WorkspaceClient; @@ -27,3 +28,7 @@ export interface WorkspaceUseCase { systematic?: boolean; order?: number; } + +export interface DataSourceAttributesWithWorkspaces extends Omit { + workspaces?: string[]; +} diff --git a/src/plugins/workspace/public/utils.test.ts b/src/plugins/workspace/public/utils.test.ts index 03aa0e208222..dfca65fcaf98 100644 --- a/src/plugins/workspace/public/utils.test.ts +++ b/src/plugins/workspace/public/utils.test.ts @@ -398,6 +398,7 @@ describe('workspace utils: getDataSourcesList', () => { auth: 'mock_value', description: 'description1', dataSourceEngineType: 'dataSourceEngineType1', + workspaces: [], }, ]); }); diff --git a/src/plugins/workspace/public/utils.ts b/src/plugins/workspace/public/utils.ts index ff3983e415d4..543a79fbc4a3 100644 --- a/src/plugins/workspace/public/utils.ts +++ b/src/plugins/workspace/public/utils.ts @@ -201,13 +201,16 @@ export const filterWorkspaceConfigurableApps = (applications: PublicAppInfo[]) = return visibleApplications; }; -export const getDataSourcesList = (client: SavedObjectsStart['client'], workspaces: string[]) => { +export const getDataSourcesList = ( + client: SavedObjectsStart['client'], + targetWorkspaces: string[] +) => { return client .find({ type: 'data-source', fields: ['id', 'title', 'auth', 'description', 'dataSourceEngineType'], perPage: 10000, - workspaces, + workspaces: targetWorkspaces, }) .then((response) => { const objects = response?.savedObjects; @@ -215,6 +218,7 @@ export const getDataSourcesList = (client: SavedObjectsStart['client'], workspac return objects.map((source) => { const id = source.id; const title = source.get('title'); + const workspaces = source.workspaces ?? []; const auth = source.get('auth'); const description = source.get('description'); const dataSourceEngineType = source.get('dataSourceEngineType'); @@ -224,6 +228,7 @@ export const getDataSourcesList = (client: SavedObjectsStart['client'], workspac auth, description, dataSourceEngineType, + workspaces, }; }); } else { From 2aa6e2741f9a2187ae5f8046c5fceff8c226668e Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Tue, 27 Aug 2024 09:30:36 -0700 Subject: [PATCH 245/276] [discover-2.0] update interfaces and services for query, data, languages (#7731) (#7863) * Initial updates to new interfaces Discover expects Signed-off-by: Kawika Avilla * [discover] update interfaces and move dataset manager (#7745) * Move dataset location Signed-off-by: Kawika Avilla * update interfaces Signed-off-by: Kawika Avilla * Update src/plugins/data/common/datasets/types.ts Co-authored-by: Ashwin P Chandran Signed-off-by: Kawika Avilla --------- Signed-off-by: Kawika Avilla Co-authored-by: Ashwin P Chandran * fix rebase errors Signed-off-by: abbyhu2000 * [discover] update interfaces and selector (#7835) * dataset handler and move manager Signed-off-by: Kawika Avilla * Adds new Data selector Signed-off-by: Ashwin P Chandran fixes loading state Signed-off-by: Ashwin P Chandran * start wiring into the selector Signed-off-by: Kawika Avilla no more white screen Signed-off-by: Kawika Avilla updating handler Signed-off-by: Kawika Avilla rendering data Signed-off-by: Kawika Avilla data structures working ok Signed-off-by: Kawika Avilla need to add datasets Signed-off-by: Kawika Avilla clean up Signed-off-by: Kawika Avilla deleted unneeded types Signed-off-by: Kawika Avilla * still working on the data structure and field Signed-off-by: Kawika Avilla * still not working. the leaf logic isnt right i believe Signed-off-by: Kawika Avilla * indices Signed-off-by: Kawika Avilla * pushing datasets Signed-off-by: Kawika Avilla * fix index pattern Signed-off-by: Kawika Avilla * fixes with column Signed-off-by: Kawika Avilla * working creation step Signed-off-by: Kawika Avilla * get dataset from state in use index pattern Signed-off-by: Kawika Avilla * dataset selector working Signed-off-by: Kawika Avilla * update ppl interceptor Signed-off-by: Kawika Avilla * add dataset service Signed-off-by: Kawika Avilla * language service Signed-off-by: Kawika Avilla * wired up but the dataset is off Signed-off-by: Kawika Avilla * Address review comments Signed-off-by: Kawika Avilla * ppl query Signed-off-by: Kawika Avilla * dql and lucene working again Signed-off-by: Kawika Avilla * fix issue that would deselect dataset Signed-off-by: Kawika Avilla * language switches and sets the query correctly Signed-off-by: Kawika Avilla * upating query Signed-off-by: Kawika Avilla * fix the styling a little Signed-off-by: Kawika Avilla * little bit width Signed-off-by: Kawika Avilla * submit on update Signed-off-by: Kawika Avilla * fix sql Signed-off-by: Kawika Avilla * ppl working better Signed-off-by: Kawika Avilla * need to still fix the aggregations Signed-off-by: Kawika Avilla * gotta fix the aggs and still need to update dql lucene dataset Signed-off-by: Kawika Avilla * use patch Signed-off-by: Kawika Avilla * Metadata slice Signed-off-by: Kawika Avilla * index pattern updates Signed-off-by: Kawika Avilla * types and datasource prepend Signed-off-by: Kawika Avilla --------- Signed-off-by: Kawika Avilla Signed-off-by: Ashwin P Chandran Co-authored-by: Ashwin P Chandran * Use language service to render query editor (#7848) * progress Signed-off-by: abbyhu2000 * get rid of setting class Signed-off-by: abbyhu2000 * register editor inside language Signed-off-by: abbyhu2000 * address commits Signed-off-by: abbyhu2000 * address more comments Signed-off-by: abbyhu2000 * change editor Signed-off-by: abbyhu2000 --------- Signed-off-by: abbyhu2000 * minor fixes (#7850) Signed-off-by: Ashwin P Chandran * [discover] Updates to mocks for tests and ci (#7852) * update manager Signed-off-by: Kawika Avilla * Extension passing Signed-off-by: Kawika Avilla * mock getIndexPatterns Signed-off-by: Kawika Avilla --------- Signed-off-by: Kawika Avilla * include create and save Signed-off-by: Kawika Avilla * Fix Nav Bar layout in New Discover (#7853) * Fix Nav Bar layout in New Discover Signed-off-by: Suchit Sahoo * Changeset file for PR #7853 created/updated --------- Signed-off-by: Suchit Sahoo Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> * [discover] keep fixing mocks (#7855) * Updating mocks still Signed-off-by: Kawika Avilla * Keep fixing mocks Signed-off-by: Kawika Avilla * update to not use getter Signed-off-by: Kawika Avilla * fix the query being updated twice Signed-off-by: Kawika Avilla * update snapshot Signed-off-by: Kawika Avilla --------- Signed-off-by: Kawika Avilla * fix remaining failures Signed-off-by: Kawika Avilla * manual changelog Signed-off-by: Kawika Avilla * update snapshot Signed-off-by: Kawika Avilla --------- Signed-off-by: Kawika Avilla Signed-off-by: abbyhu2000 Signed-off-by: Ashwin P Chandran Signed-off-by: Suchit Sahoo Co-authored-by: Ashwin P Chandran Co-authored-by: abbyhu2000 Co-authored-by: Ashwin P Chandran Co-authored-by: Suchit Sahoo <38322563+LDrago27@users.noreply.github.com> Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> (cherry picked from commit 1976ecfd223bb8cb2462b2779d1b7af97016c476) --- changelogs/fragments/7731.yml | 2 + package.json | 2 +- .../config/global_selectors.json | 3 +- .../saved_objects/saved_objects_client.ts | 6 +- .../dashboard_top_nav.test.tsx.snap | 138 ++++----- .../saved_objects/migrate_match_all_query.ts | 4 +- src/plugins/data/common/constants.ts | 37 +++ src/plugins/data/common/data_frames/types.ts | 2 +- src/plugins/data/common/data_frames/utils.ts | 12 +- src/plugins/data/common/data_sets/types.ts | 38 --- .../data/common/datasets/_structure_cache.ts | 46 +++ .../common/{data_sets => datasets}/index.ts | 0 src/plugins/data/common/datasets/types.ts | 251 ++++++++++++++++ src/plugins/data/common/index.ts | 2 +- .../index_patterns/index_patterns.ts | 1 + src/plugins/data/common/query/types.ts | 3 + .../search/search_source/search_source.ts | 14 +- src/plugins/data/common/types.ts | 7 +- .../data/public/antlr/dql/code_completion.ts | 7 +- .../antlr/opensearch_sql/code_completion.ts | 4 +- .../data/public/antlr/shared/utils.test.ts | 45 ++- src/plugins/data/public/antlr/shared/utils.ts | 26 +- src/plugins/data/public/index.ts | 16 +- src/plugins/data/public/mocks.ts | 11 +- src/plugins/data/public/plugin.ts | 16 +- .../dataset_manager/dataset_manager.mock.ts | 24 -- .../dataset_manager/dataset_manager.test.ts | 35 --- .../query/dataset_manager/dataset_manager.ts | 114 -------- src/plugins/data/public/query/index.tsx | 4 +- src/plugins/data/public/query/mocks.ts | 11 +- .../data/public/query/query_service.ts | 44 +-- .../dataset_service/dataset_service.mock.ts | 50 ++++ .../dataset_service/dataset_service.ts | 124 ++++++++ .../query_string/dataset_service/index.ts | 7 + .../dataset_service/lib}/index.ts | 3 +- .../dataset_service/lib/index_pattern_type.ts | 125 ++++++++ .../dataset_service/lib/index_type.ts | 140 +++++++++ .../query_string/dataset_service/types.ts | 47 +++ .../data/public/query/query_string/index.ts | 7 + .../query_string/language_service/index.ts | 7 + .../language_service/language_service.mock.ts | 69 +++++ .../language_service/language_service.ts | 145 +++++++++ .../language_service/lib/dql_language.ts | 28 ++ .../language_service/lib}/index.ts | 3 +- .../language_service/lib/lucene_language.ts | 28 ++ .../query_string/language_service/types.ts | 30 ++ .../query/query_string/query_history.ts | 6 +- .../query_string/query_string_manager.mock.ts | 27 +- .../query_string/query_string_manager.test.ts | 13 +- .../query_string/query_string_manager.ts | 79 ++++- .../state_sync/connect_to_query_state.test.ts | 13 + .../state_sync/connect_to_query_state.ts | 70 +---- .../create_global_query_observable.ts | 8 - .../query/state_sync/sync_state_with_url.ts | 12 +- .../data/public/query/state_sync/types.ts | 5 +- src/plugins/data/public/query/types.ts | 48 +++ src/plugins/data/public/search/index.ts | 2 +- src/plugins/data/public/search/mocks.ts | 1 + .../data/public/search/search_service.ts | 45 +-- src/plugins/data/public/search/types.ts | 1 + src/plugins/data/public/types.ts | 6 +- src/plugins/data/public/ui/_index.scss | 2 +- .../dataset_navigator/_dataset_navigator.scss | 31 -- .../public/ui/dataset_navigator/_index.scss | 1 - .../create_dataset_navigator.tsx | 26 -- .../lib/catalog_cache/cache_intercept.ts | 23 -- .../lib/catalog_cache/index.tsx | 8 - .../public/ui/dataset_navigator/lib/index.tsx | 8 - .../lib/utils/fetch_catalog_cache_status.ts | 26 -- .../lib/utils/fetch_data_sources.ts | 22 -- .../lib/utils/fetch_index_patterns.ts | 34 --- .../lib/utils/fetch_indices.ts | 46 --- .../lib/utils/use_polling.ts | 137 --------- .../dataset_selector/_dataset_explorer.scss | 28 ++ .../dataset_selector/_dataset_selector.scss | 14 + .../public/ui/dataset_selector/_index.scss | 2 + .../ui/dataset_selector/advanced_selector.tsx | 70 +++++ .../ui/dataset_selector/configurator.tsx | 161 ++++++++++ .../ui/dataset_selector/dataset_explorer.tsx | 228 +++++++++++++++ .../ui/dataset_selector/dataset_selector.tsx | 196 +++++++++++++ .../data/public/ui/dataset_selector/index.tsx | 49 ++++ src/plugins/data/public/ui/index.ts | 26 +- src/plugins/data/public/ui/mocks.ts | 37 +-- .../language_selector.test.tsx.snap | 18 +- .../public/ui/query_editor/_query_editor.scss | 7 +- .../editors/default_editor/index.tsx | 2 +- .../query_editor/editors/dql_editor/index.tsx | 2 +- .../public/ui/query_editor/editors/shared.tsx | 2 +- .../data/public/ui/query_editor/index.tsx | 2 + .../query_editor/language_selector.test.tsx | 43 +-- .../ui/query_editor/language_selector.tsx | 71 +++-- .../ui/query_editor/no_data_popover.tsx | 4 +- .../public/ui/query_editor/query_editor.tsx | 276 ++++-------------- .../ui/query_editor/query_editor_top_row.tsx | 61 +--- .../ui/search_bar/create_search_bar.tsx | 24 +- .../data/public/ui/search_bar/index.tsx | 1 + .../ui/search_bar/lib/use_dataset_manager.ts | 39 --- .../lib/use_query_string_manager.ts | 35 ++- .../public/ui/search_bar/search_bar.test.tsx | 20 ++ .../data/public/ui/search_bar/search_bar.tsx | 58 ++-- src/plugins/data/public/ui/settings/mocks.ts | 18 -- src/plugins/data/public/ui/types.ts | 59 +--- src/plugins/data/public/ui/ui_service.ts | 43 +-- .../data/server/search/search_service.ts | 25 +- .../public/components/app_container.tsx | 2 +- .../public/components/sidebar/index.test.tsx | 11 +- .../public/components/sidebar/index.tsx | 59 +--- .../utils/state_management/metadata_slice.ts | 16 +- .../state_management/redux_persistence.ts | 41 ++- .../public/utils/state_management/store.ts | 2 +- .../utils/state_management/index.ts | 3 +- .../view_components/canvas/index.tsx | 10 +- .../view_components/canvas/top_nav.tsx | 26 +- .../utils/update_search_source.ts | 27 +- .../utils/use_dataset_manager.ts | 39 --- .../utils/use_index_pattern.ts | 50 +--- .../view_components/utils/use_search.ts | 18 +- src/plugins/discover/public/plugin.ts | 8 +- .../public/state_management/url/errors.ts | 2 + .../query_enhancements/common/utils.ts | 10 +- .../public/assets/s3_mark.svg | 9 + .../public/datasets/index.ts | 6 + .../public/datasets}/requests/index.tsx | 0 .../public/datasets}/requests/sql.ts | 0 .../public/datasets/s3_handler.ts | 113 +++++++ .../datasets}/utils/query_session_utils.ts | 0 .../query_enhancements/public/plugin.tsx | 98 +++---- .../components/query_assist_bar.tsx | 18 +- .../utils/create_extension.test.tsx | 18 +- .../query_assist/utils/create_extension.tsx | 12 +- .../public/search/ppl_search_interceptor.ts | 97 ++---- .../public/search/sql_search_interceptor.ts | 57 +--- .../query_enhancements/server/routes/index.ts | 4 +- .../server/search/ppl_search_strategy.ts | 31 +- .../search/sql_async_search_strategy.ts | 16 +- .../server/search/sql_search_strategy.ts | 1 - .../query_enhancements/server/utils/facet.ts | 10 +- 137 files changed, 2853 insertions(+), 2020 deletions(-) create mode 100644 changelogs/fragments/7731.yml delete mode 100644 src/plugins/data/common/data_sets/types.ts create mode 100644 src/plugins/data/common/datasets/_structure_cache.ts rename src/plugins/data/common/{data_sets => datasets}/index.ts (100%) create mode 100644 src/plugins/data/common/datasets/types.ts delete mode 100644 src/plugins/data/public/query/dataset_manager/dataset_manager.mock.ts delete mode 100644 src/plugins/data/public/query/dataset_manager/dataset_manager.test.ts delete mode 100644 src/plugins/data/public/query/dataset_manager/dataset_manager.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/dataset_service.mock.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/index.ts rename src/plugins/data/public/query/{dataset_manager => query_string/dataset_service/lib}/index.ts (54%) create mode 100644 src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts create mode 100644 src/plugins/data/public/query/query_string/dataset_service/types.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/index.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/language_service.mock.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/language_service.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts rename src/plugins/data/public/{ui/settings => query/query_string/language_service/lib}/index.ts (54%) create mode 100644 src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts create mode 100644 src/plugins/data/public/query/query_string/language_service/types.ts create mode 100644 src/plugins/data/public/query/types.ts delete mode 100644 src/plugins/data/public/ui/dataset_navigator/_dataset_navigator.scss delete mode 100644 src/plugins/data/public/ui/dataset_navigator/_index.scss delete mode 100644 src/plugins/data/public/ui/dataset_navigator/create_dataset_navigator.tsx delete mode 100644 src/plugins/data/public/ui/dataset_navigator/lib/catalog_cache/cache_intercept.ts delete mode 100644 src/plugins/data/public/ui/dataset_navigator/lib/catalog_cache/index.tsx delete mode 100644 src/plugins/data/public/ui/dataset_navigator/lib/index.tsx delete mode 100644 src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_catalog_cache_status.ts delete mode 100644 src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_data_sources.ts delete mode 100644 src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_index_patterns.ts delete mode 100644 src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_indices.ts delete mode 100644 src/plugins/data/public/ui/dataset_navigator/lib/utils/use_polling.ts create mode 100644 src/plugins/data/public/ui/dataset_selector/_dataset_explorer.scss create mode 100644 src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss create mode 100644 src/plugins/data/public/ui/dataset_selector/_index.scss create mode 100644 src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx create mode 100644 src/plugins/data/public/ui/dataset_selector/configurator.tsx create mode 100644 src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx create mode 100644 src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx create mode 100644 src/plugins/data/public/ui/dataset_selector/index.tsx delete mode 100644 src/plugins/data/public/ui/search_bar/lib/use_dataset_manager.ts delete mode 100644 src/plugins/data/public/ui/settings/mocks.ts delete mode 100644 src/plugins/discover/public/application/view_components/utils/use_dataset_manager.ts create mode 100644 src/plugins/query_enhancements/public/assets/s3_mark.svg create mode 100644 src/plugins/query_enhancements/public/datasets/index.ts rename src/plugins/{data/public/ui/dataset_navigator/lib => query_enhancements/public/datasets}/requests/index.tsx (100%) rename src/plugins/{data/public/ui/dataset_navigator/lib => query_enhancements/public/datasets}/requests/sql.ts (100%) create mode 100644 src/plugins/query_enhancements/public/datasets/s3_handler.ts rename src/plugins/{data/public/ui/dataset_navigator/lib => query_enhancements/public/datasets}/utils/query_session_utils.ts (100%) diff --git a/changelogs/fragments/7731.yml b/changelogs/fragments/7731.yml new file mode 100644 index 000000000000..cab14565e6b7 --- /dev/null +++ b/changelogs/fragments/7731.yml @@ -0,0 +1,2 @@ +refactor: +- Multi-datasources and multi-query languages features to use generic structured types, abstract data querying, and the language service ([#7731](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7731)) \ No newline at end of file diff --git a/package.json b/package.json index 420c19f30f6a..283cd8b5bfcb 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "start": "scripts/use_node scripts/opensearch_dashboards --dev", "start:docker": "scripts/use_node scripts/opensearch_dashboards --dev --opensearch.hosts=$OPENSEARCH_HOSTS --opensearch.ignoreVersionMismatch=true --server.host=$SERVER_HOST", "start:security": "scripts/use_node scripts/opensearch_dashboards --dev --security", - "start:enhancements": "scripts/use_node scripts/opensearch_dashboards --dev --uiSettings.overrides['query:enhancements:enabled']=true --uiSettings.overrides['home:useNewHomePage']=true --uiSettings.overrides['state:storeInSessionStorage']=true", + "start:enhancements": "scripts/use_node scripts/opensearch_dashboards --dev --uiSettings.overrides['query:enhancements:enabled']=true --uiSettings.overrides['home:useNewHomePage']=true", "debug": "scripts/use_node --nolazy --inspect scripts/opensearch_dashboards --dev", "debug-break": "scripts/use_node --nolazy --inspect-brk scripts/opensearch_dashboards --dev", "lint": "yarn run lint:es && yarn run lint:style", diff --git a/packages/osd-stylelint-config/config/global_selectors.json b/packages/osd-stylelint-config/config/global_selectors.json index 1da8137e9a7a..ca442760f731 100644 --- a/packages/osd-stylelint-config/config/global_selectors.json +++ b/packages/osd-stylelint-config/config/global_selectors.json @@ -27,8 +27,7 @@ "src/plugins/discover/public/application/view_components/canvas/discover_canvas.scss", "src/plugins/discover/public/application/components/sidebar/discover_sidebar.scss", "src/plugins/data/public/ui/query_string_input/_query_bar.scss", - "src/plugins/data/public/ui/query_editor/_query_editor.scss", - "src/plugins/data/public/ui/dataset_navigator/_dataset_navigator.scss" + "src/plugins/data/public/ui/query_editor/_query_editor.scss" ] } } \ No newline at end of file diff --git a/src/core/public/saved_objects/saved_objects_client.ts b/src/core/public/saved_objects/saved_objects_client.ts index ad934e0a73ae..9dc6a84b484a 100644 --- a/src/core/public/saved_objects/saved_objects_client.ts +++ b/src/core/public/saved_objects/saved_objects_client.ts @@ -457,14 +457,14 @@ export class SavedObjectsClient { * { id: 'foo', type: 'index-pattern' } * ]) */ - public bulkGet = (objects: Array<{ id: string; type: string }> = []) => { + public bulkGet = (objects: Array<{ id: string; type: string }> = []) => { const filteredObjects = objects.map((obj) => pick(obj, ['id', 'type'])); return this.performBulkGet(filteredObjects).then((resp) => { resp.saved_objects = resp.saved_objects.map((d) => this.createSavedObject(d)); return renameKeys< PromiseType>, - SavedObjectsBatchResponse - >({ saved_objects: 'savedObjects' }, resp) as SavedObjectsBatchResponse; + SavedObjectsBatchResponse + >({ saved_objects: 'savedObjects' }, resp) as SavedObjectsBatchResponse; }); }; diff --git a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap index 637852c448e3..9003cc444c81 100644 --- a/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap +++ b/src/plugins/dashboard/public/application/components/dashboard_top_nav/__snapshots__/dashboard_top_nav.test.tsx.snap @@ -325,15 +325,6 @@ exports[`Dashboard top nav render in embed mode 1`] = ` }, "query": Object { "addToQueryLog": [MockFunction], - "dataSetManager": Object { - "fetchDefaultDataSet": [MockFunction], - "getDataSet": [MockFunction], - "getDefaultDataSet": [MockFunction], - "getUpdates$": [MockFunction], - "init": [MockFunction], - "initWithIndexPattern": [MockFunction], - "setDataSet": [MockFunction], - }, "filterManager": Object { "addFilters": [MockFunction], "getAppFilters": [MockFunction], @@ -352,10 +343,19 @@ exports[`Dashboard top nav render in embed mode 1`] = ` }, "getOpenSearchQuery": [MockFunction], "queryString": Object { + "addToQueryHistory": [MockFunction], + "changeQueryHistory": [MockFunction], "clearQuery": [MockFunction], + "clearQueryHistory": [MockFunction], "formatQuery": [MockFunction], + "getDatasetService": [MockFunction], "getDefaultQuery": [MockFunction], + "getInitialQuery": [MockFunction], + "getInitialQueryByDataset": [MockFunction], + "getInitialQueryByLanguage": [MockFunction], + "getLanguageService": [MockFunction], "getQuery": [MockFunction], + "getQueryHistory": [MockFunction], "getUpdates$": [MockFunction], "setQuery": [MockFunction], }, @@ -417,14 +417,9 @@ exports[`Dashboard top nav render in embed mode 1`] = ` "showError": [MockFunction], }, "ui": Object { - "DataSetNavigator": [MockFunction], "IndexPatternSelect": [MockFunction], "SearchBar": [MockFunction], - "Settings": undefined, "SuggestionsComponent": [MockFunction], - "dataSetContainer$": Observable { - "_isScalar": false, - }, }, }, "docLinks": Object { @@ -1391,15 +1386,6 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = }, "query": Object { "addToQueryLog": [MockFunction], - "dataSetManager": Object { - "fetchDefaultDataSet": [MockFunction], - "getDataSet": [MockFunction], - "getDefaultDataSet": [MockFunction], - "getUpdates$": [MockFunction], - "init": [MockFunction], - "initWithIndexPattern": [MockFunction], - "setDataSet": [MockFunction], - }, "filterManager": Object { "addFilters": [MockFunction], "getAppFilters": [MockFunction], @@ -1418,10 +1404,19 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = }, "getOpenSearchQuery": [MockFunction], "queryString": Object { + "addToQueryHistory": [MockFunction], + "changeQueryHistory": [MockFunction], "clearQuery": [MockFunction], + "clearQueryHistory": [MockFunction], "formatQuery": [MockFunction], + "getDatasetService": [MockFunction], "getDefaultQuery": [MockFunction], + "getInitialQuery": [MockFunction], + "getInitialQueryByDataset": [MockFunction], + "getInitialQueryByLanguage": [MockFunction], + "getLanguageService": [MockFunction], "getQuery": [MockFunction], + "getQueryHistory": [MockFunction], "getUpdates$": [MockFunction], "setQuery": [MockFunction], }, @@ -1483,14 +1478,9 @@ exports[`Dashboard top nav render in embed mode, and force hide filter bar 1`] = "showError": [MockFunction], }, "ui": Object { - "DataSetNavigator": [MockFunction], "IndexPatternSelect": [MockFunction], "SearchBar": [MockFunction], - "Settings": undefined, "SuggestionsComponent": [MockFunction], - "dataSetContainer$": Observable { - "_isScalar": false, - }, }, }, "docLinks": Object { @@ -2457,15 +2447,6 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b }, "query": Object { "addToQueryLog": [MockFunction], - "dataSetManager": Object { - "fetchDefaultDataSet": [MockFunction], - "getDataSet": [MockFunction], - "getDefaultDataSet": [MockFunction], - "getUpdates$": [MockFunction], - "init": [MockFunction], - "initWithIndexPattern": [MockFunction], - "setDataSet": [MockFunction], - }, "filterManager": Object { "addFilters": [MockFunction], "getAppFilters": [MockFunction], @@ -2484,10 +2465,19 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b }, "getOpenSearchQuery": [MockFunction], "queryString": Object { + "addToQueryHistory": [MockFunction], + "changeQueryHistory": [MockFunction], "clearQuery": [MockFunction], + "clearQueryHistory": [MockFunction], "formatQuery": [MockFunction], + "getDatasetService": [MockFunction], "getDefaultQuery": [MockFunction], + "getInitialQuery": [MockFunction], + "getInitialQueryByDataset": [MockFunction], + "getInitialQueryByLanguage": [MockFunction], + "getLanguageService": [MockFunction], "getQuery": [MockFunction], + "getQueryHistory": [MockFunction], "getUpdates$": [MockFunction], "setQuery": [MockFunction], }, @@ -2549,14 +2539,9 @@ exports[`Dashboard top nav render in embed mode, components can be forced show b "showError": [MockFunction], }, "ui": Object { - "DataSetNavigator": [MockFunction], "IndexPatternSelect": [MockFunction], "SearchBar": [MockFunction], - "Settings": undefined, "SuggestionsComponent": [MockFunction], - "dataSetContainer$": Observable { - "_isScalar": false, - }, }, }, "docLinks": Object { @@ -3523,15 +3508,6 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu }, "query": Object { "addToQueryLog": [MockFunction], - "dataSetManager": Object { - "fetchDefaultDataSet": [MockFunction], - "getDataSet": [MockFunction], - "getDefaultDataSet": [MockFunction], - "getUpdates$": [MockFunction], - "init": [MockFunction], - "initWithIndexPattern": [MockFunction], - "setDataSet": [MockFunction], - }, "filterManager": Object { "addFilters": [MockFunction], "getAppFilters": [MockFunction], @@ -3550,10 +3526,19 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu }, "getOpenSearchQuery": [MockFunction], "queryString": Object { + "addToQueryHistory": [MockFunction], + "changeQueryHistory": [MockFunction], "clearQuery": [MockFunction], + "clearQueryHistory": [MockFunction], "formatQuery": [MockFunction], + "getDatasetService": [MockFunction], "getDefaultQuery": [MockFunction], + "getInitialQuery": [MockFunction], + "getInitialQueryByDataset": [MockFunction], + "getInitialQueryByLanguage": [MockFunction], + "getLanguageService": [MockFunction], "getQuery": [MockFunction], + "getQueryHistory": [MockFunction], "getUpdates$": [MockFunction], "setQuery": [MockFunction], }, @@ -3615,14 +3600,9 @@ exports[`Dashboard top nav render in full screen mode with appended URL param bu "showError": [MockFunction], }, "ui": Object { - "DataSetNavigator": [MockFunction], "IndexPatternSelect": [MockFunction], "SearchBar": [MockFunction], - "Settings": undefined, "SuggestionsComponent": [MockFunction], - "dataSetContainer$": Observable { - "_isScalar": false, - }, }, }, "docLinks": Object { @@ -4589,15 +4569,6 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be }, "query": Object { "addToQueryLog": [MockFunction], - "dataSetManager": Object { - "fetchDefaultDataSet": [MockFunction], - "getDataSet": [MockFunction], - "getDefaultDataSet": [MockFunction], - "getUpdates$": [MockFunction], - "init": [MockFunction], - "initWithIndexPattern": [MockFunction], - "setDataSet": [MockFunction], - }, "filterManager": Object { "addFilters": [MockFunction], "getAppFilters": [MockFunction], @@ -4616,10 +4587,19 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be }, "getOpenSearchQuery": [MockFunction], "queryString": Object { + "addToQueryHistory": [MockFunction], + "changeQueryHistory": [MockFunction], "clearQuery": [MockFunction], + "clearQueryHistory": [MockFunction], "formatQuery": [MockFunction], + "getDatasetService": [MockFunction], "getDefaultQuery": [MockFunction], + "getInitialQuery": [MockFunction], + "getInitialQueryByDataset": [MockFunction], + "getInitialQueryByLanguage": [MockFunction], + "getLanguageService": [MockFunction], "getQuery": [MockFunction], + "getQueryHistory": [MockFunction], "getUpdates$": [MockFunction], "setQuery": [MockFunction], }, @@ -4681,14 +4661,9 @@ exports[`Dashboard top nav render in full screen mode, no componenets should be "showError": [MockFunction], }, "ui": Object { - "DataSetNavigator": [MockFunction], "IndexPatternSelect": [MockFunction], "SearchBar": [MockFunction], - "Settings": undefined, "SuggestionsComponent": [MockFunction], - "dataSetContainer$": Observable { - "_isScalar": false, - }, }, }, "docLinks": Object { @@ -5655,15 +5630,6 @@ exports[`Dashboard top nav render with all components 1`] = ` }, "query": Object { "addToQueryLog": [MockFunction], - "dataSetManager": Object { - "fetchDefaultDataSet": [MockFunction], - "getDataSet": [MockFunction], - "getDefaultDataSet": [MockFunction], - "getUpdates$": [MockFunction], - "init": [MockFunction], - "initWithIndexPattern": [MockFunction], - "setDataSet": [MockFunction], - }, "filterManager": Object { "addFilters": [MockFunction], "getAppFilters": [MockFunction], @@ -5682,10 +5648,19 @@ exports[`Dashboard top nav render with all components 1`] = ` }, "getOpenSearchQuery": [MockFunction], "queryString": Object { + "addToQueryHistory": [MockFunction], + "changeQueryHistory": [MockFunction], "clearQuery": [MockFunction], + "clearQueryHistory": [MockFunction], "formatQuery": [MockFunction], + "getDatasetService": [MockFunction], "getDefaultQuery": [MockFunction], + "getInitialQuery": [MockFunction], + "getInitialQueryByDataset": [MockFunction], + "getInitialQueryByLanguage": [MockFunction], + "getLanguageService": [MockFunction], "getQuery": [MockFunction], + "getQueryHistory": [MockFunction], "getUpdates$": [MockFunction], "setQuery": [MockFunction], }, @@ -5747,14 +5722,9 @@ exports[`Dashboard top nav render with all components 1`] = ` "showError": [MockFunction], }, "ui": Object { - "DataSetNavigator": [MockFunction], "IndexPatternSelect": [MockFunction], "SearchBar": [MockFunction], - "Settings": undefined, "SuggestionsComponent": [MockFunction], - "dataSetContainer$": Observable { - "_isScalar": false, - }, }, }, "docLinks": Object { diff --git a/src/plugins/dashboard/server/saved_objects/migrate_match_all_query.ts b/src/plugins/dashboard/server/saved_objects/migrate_match_all_query.ts index 8275d2206b0e..b51121df8ddb 100644 --- a/src/plugins/dashboard/server/saved_objects/migrate_match_all_query.ts +++ b/src/plugins/dashboard/server/saved_objects/migrate_match_all_query.ts @@ -30,7 +30,7 @@ import { SavedObjectMigrationFn } from 'opensearch-dashboards/server'; import { get } from 'lodash'; -import { DEFAULT_QUERY_LANGUAGE } from '../../../data/common'; +import { DEFAULT_QUERY } from '../../../data/common'; /** * This migration script is related to: @@ -61,7 +61,7 @@ export const migrateMatchAllQuery: SavedObjectMigrationFn = (doc) => { ...searchSource, query: { query: '', - language: DEFAULT_QUERY_LANGUAGE, + language: DEFAULT_QUERY.LANGUAGE, }, }), }, diff --git a/src/plugins/data/common/constants.ts b/src/plugins/data/common/constants.ts index 1de7ae5df034..97c465762986 100644 --- a/src/plugins/data/common/constants.ts +++ b/src/plugins/data/common/constants.ts @@ -9,6 +9,8 @@ * GitHub history for details. */ +import { DATA_STRUCTURE_META_TYPES, DataStructure } from './types'; + /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -28,8 +30,43 @@ * under the License. */ +export const DEFAULT_DATA = { + STRUCTURES: { + ROOT: { + id: 'ROOT', + title: 'Data', + type: 'ROOT', + meta: { + type: DATA_STRUCTURE_META_TYPES.FEATURE, + icon: 'folderOpen', + tooltip: 'Root Data Structure', + }, + } as DataStructure, + }, + + SET_TYPES: { + INDEX_PATTERN: 'INDEX_PATTERN', + INDEX: 'INDEXES', + }, + + SOURCE_TYPES: { + OPENSEARCH: 'OpenSearch', + LEGACY: 'LEGACY', + }, +}; + export const DEFAULT_QUERY_LANGUAGE = 'kuery'; +export const DEFAULT_QUERY = { + LANGUAGE: DEFAULT_QUERY_LANGUAGE, + DATASET: { + TYPE: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + DATASOURCE: { + TYPE: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, + }, + }, +}; + export const UI_SETTINGS = { META_FIELDS: 'metaFields', DOC_HIGHLIGHT: 'doc_table:highlight', diff --git a/src/plugins/data/common/data_frames/types.ts b/src/plugins/data/common/data_frames/types.ts index 1b0f3ee1fedb..978f2817bcf4 100644 --- a/src/plugins/data/common/data_frames/types.ts +++ b/src/plugins/data/common/data_frames/types.ts @@ -17,7 +17,7 @@ export enum DATA_FRAME_TYPES { export interface DataFrameService { get: () => IDataFrame | undefined; - set: (dataFrame: IDataFrame) => Promise; + set: (dataFrame: IDataFrame) => void; clear: () => void; } diff --git a/src/plugins/data/common/data_frames/utils.ts b/src/plugins/data/common/data_frames/utils.ts index c5303e0260b4..8c9f63b0f0d3 100644 --- a/src/plugins/data/common/data_frames/utils.ts +++ b/src/plugins/data/common/data_frames/utils.ts @@ -18,7 +18,7 @@ import { import { IFieldType } from './fields'; import { IndexPatternFieldMap, IndexPatternSpec } from '../index_patterns'; import { IOpenSearchDashboardsSearchRequest } from '../search'; -import { GetAggTypeFn, GetDataFrameAggQsFn, TimeRange } from '../types'; +import { GetAggTypeFn, GetDataFrameAggQsFn, Query, TimeRange } from '../types'; /** * Returns the raw data frame from the search request. @@ -380,25 +380,25 @@ export const createDataFrame = (partial: PartialDataFrame): IDataFrame | IDataFr */ export const updateDataFrameMeta = ({ dataFrame, - qs, + query, aggConfig, timeField, timeFilter, getAggQsFn, }: { dataFrame: IDataFrame; - qs: string; + query: Query; aggConfig: DataFrameAggConfig; timeField: any; timeFilter: string; getAggQsFn: GetDataFrameAggQsFn; }) => { dataFrame.meta = { - ...dataFrame.meta, + ...dataFrame?.meta, aggs: aggConfig, aggsQs: { [aggConfig.id]: getAggQsFn({ - qs, + query, aggConfig, timeField, timeFilter, @@ -411,7 +411,7 @@ export const updateDataFrameMeta = ({ for (const [key, subAgg] of Object.entries(subAggs)) { const subAggConfig: Record = { [key]: subAgg }; dataFrame.meta.aggsQs[subAgg.id] = getAggQsFn({ - qs, + query, aggConfig: subAggConfig as DataFrameAggConfig, timeField, timeFilter, diff --git a/src/plugins/data/common/data_sets/types.ts b/src/plugins/data/common/data_sets/types.ts deleted file mode 100644 index 23ab74bed030..000000000000 --- a/src/plugins/data/common/data_sets/types.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -/** @public **/ -export enum SIMPLE_DATA_SOURCE_TYPES { - DEFAULT = 'data-source', - EXTERNAL = 'external-source', -} - -/** @public **/ -export enum SIMPLE_DATA_SET_TYPES { - INDEX_PATTERN = 'index-pattern', - TEMPORARY = 'temporary', - TEMPORARY_ASYNC = 'temporary-async', -} - -export interface SimpleObject { - id: string; - title?: string; - dataSourceRef?: SimpleDataSource; -} - -export interface SimpleDataSource { - id: string; - name: string; - indices?: SimpleObject[]; - tables?: SimpleObject[]; - type: SIMPLE_DATA_SOURCE_TYPES; -} - -export interface SimpleDataSet extends SimpleObject { - fields?: any[]; - timeFieldName?: string; - timeFields?: any[]; - type?: SIMPLE_DATA_SET_TYPES; -} diff --git a/src/plugins/data/common/datasets/_structure_cache.ts b/src/plugins/data/common/datasets/_structure_cache.ts new file mode 100644 index 000000000000..1799d4638134 --- /dev/null +++ b/src/plugins/data/common/datasets/_structure_cache.ts @@ -0,0 +1,46 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { DataStructure, CachedDataStructure } from './types'; + +export interface DataStructureCache { + get: (id: string) => CachedDataStructure | undefined; + set: (id: string, value: CachedDataStructure) => CachedDataStructure; + clear: (id: string) => void; + clearAll: () => void; +} + +export function createDataStructureCache(): DataStructureCache { + const cache: Record = {}; + + const dataStructureCache: DataStructureCache = { + get: (id: string) => { + return cache[id]; + }, + set: (id: string, value: CachedDataStructure) => { + cache[id] = value; + return value; + }, + clear: (id: string) => { + delete cache[id]; + }, + // TODO: call this on log out + clearAll: () => { + Object.keys(cache).forEach((key) => delete cache[key]); + }, + }; + + return dataStructureCache; +} + +export function toCachedDataStructure(dataStructure: DataStructure): CachedDataStructure { + return { + id: dataStructure.id, + title: dataStructure.title, + type: dataStructure.type, + parent: dataStructure.parent?.id || '', + children: dataStructure.children?.map((child) => child.id) || [], + }; +} diff --git a/src/plugins/data/common/data_sets/index.ts b/src/plugins/data/common/datasets/index.ts similarity index 100% rename from src/plugins/data/common/data_sets/index.ts rename to src/plugins/data/common/datasets/index.ts diff --git a/src/plugins/data/common/datasets/types.ts b/src/plugins/data/common/datasets/types.ts new file mode 100644 index 000000000000..69549a631ab9 --- /dev/null +++ b/src/plugins/data/common/datasets/types.ts @@ -0,0 +1,251 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiIconProps } from '@elastic/eui'; +export * from './_structure_cache'; + +/** + * Describes a data source with its properties. + */ +export interface DataSource { + /** Optional unique identifier for the data source, if MDS enabled this is the ID used to fetch the data source */ + id?: string; + /** Human-readable name of the data source */ + title: string; + /** The engine type of the data source */ + type: string; + /** Optional metadata for the data source */ + meta?: DataSourceMeta; +} + +/** + * Metadata for a data source, generic to allow for additional fields. + */ +export interface DataSourceMeta { + /** Optional name used for specific purposes like async query sources */ + name?: string; + /** Optional session ID for faster responses when utilizing async query sources */ + sessionId?: string; +} + +/** + * Represents the hierarchical structure of data within a data source. + * + * @example + * + * const openSearchCluster: DataStructure = { + * id: "b18e5f58-cf71-11ee-ad92-2468ce360004", + * title: "Data Cluster1", + * type: "DATA_SOURCE", + * children: [ + * { + * id: "b18e5f58-cf71-11ee-ad92-2468ce360004::logs-2023.05", + * title: "logs-2023.05", + * type: "INDEX", + * parent: { id: "b18e5f58-cf71-11ee-ad92-2468ce360004", title: "Data Cluster1", type: "DATA_SOURCE" }, + * meta: { + * type: 'FEATURE', + * icon: 'indexIcon', + * tooltip: 'Logs from May 2023' + * } + * }, + * { + * id: "b18e5f58-cf71-11ee-ad92-2468ce360004::logs-2023.06", + * title: "logs-2023.06", + * type: "INDEX", + * parent: { id: "b18e5f58-cf71-11ee-ad92-2468ce360004", title: "Data Cluster1", type: "DATA_SOURCE" }, + * meta: { + * type: 'FEATURE', + * icon: 'indexIcon', + * tooltip: 'Logs from June 2023' + * } + * } + * ], + * meta: { + * type: 'FEATURE', + * icon: 'clusterIcon', + * tooltip: 'OpenSearch Cluster' + * } + * }; + * + * Example of an S3 data source with a connection, database, and tables: + * + * const s3DataSource: DataStructure = { + * id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003", + * title: "Flint MDS cluster name", + * type: "DATA_SOURCE", + * children: [ + * { + * id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003::mys3", + * title: "mys3", + * type: "CONNECTION", + * parent: { id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003", title: "Flint MDS cluster name", type: "DATA_SOURCE" }, + * children: [ + * { + * id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003::mys3.defaultDb", + * title: "defaultDb", + * type: "DATABASE", + * parent: { id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003::mys3", title: "mys3", type: "CONNECTION" }, + * children: [ + * { + * id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003::mys3.defaultDb.table1", + * title: "table1", + * type: "TABLE", + * parent: { id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003::mys3.defaultDb", title: "defaultDb", type: "DATABASE" } + * }, + * { + * id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003::mys3.defaultDb.table2", + * title: "table2", + * type: "TABLE", + * parent: { id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003::mys3.defaultDb", title: "defaultDb", type: "DATABASE" } + * } + * ] + * } + * ] + * } + * ] + * }; + */ +export interface DataStructure { + /** Unique identifier for the data structure. */ + id: string; + /** Human-readable name of the data structure */ + title: string; + /** The type of the data structure */ + type: string; + /** Optional reference to the parent data structure */ + parent?: DataStructure; + /** Optional array of child data structures */ + children?: DataStructure[]; + hasNext?: boolean; + columnHeader?: string; + /** Optional metadata for the data structure */ + meta?: DataStructureMeta; +} + +/** + * DataStructureMeta types + */ +export enum DATA_STRUCTURE_META_TYPES { + FEATURE = 'FEATURE', + TYPE = 'TYPE', + CUSTOM = 'CUSTOM', +} + +/** + * Metadata for a data structure, used for additional properties like icons or tooltips. + */ +export interface DataStructureFeatureMeta { + type: DATA_STRUCTURE_META_TYPES.FEATURE; + icon?: string; + tooltip?: string; +} + +/** + * Metadata for dataset type + */ +export interface DataStructureDataTypeMeta { + type: DATA_STRUCTURE_META_TYPES.TYPE; + icon: EuiIconProps; + tooltip: string; +} + +/** + * Metadata for a data structure with CUSTOM type, allowing any additional fields. + */ +export interface DataStructureCustomMeta { + type: DATA_STRUCTURE_META_TYPES.CUSTOM; + [key: string]: any; +} + +/** + * Union type for DataStructureMeta + */ +export type DataStructureMeta = + | DataStructureFeatureMeta + | DataStructureDataTypeMeta + | DataStructureCustomMeta; + +/** + * Represents a cached version of DataStructure with string references instead of object references. + * + * @example + * + * const cachedOpenSearchCluster: CachedDataStructure = { + * id: "b18e5f58-cf71-11ee-ad92-2468ce360004", + * title: "Data Cluster1", + * type: "DATA_SOURCE", + * parent: "", + * children: [ + * "b18e5f58-cf71-11ee-ad92-2468ce360004::logs-2023.05", + * "b18e5f58-cf71-11ee-ad92-2468ce360004::logs-2023.06" + * ] + * }; + */ +export interface CachedDataStructure extends Omit { + /** ID of the parent data structure */ + parent: string; + /** Array of child data structure IDs */ + children: string[]; +} + +export interface BaseDataset { + /** Unique identifier for the dataset, for non-index pattern based datasets, we will append the data source ID if present */ + id: string; + /** Human-readable name of the dataset that is used to query */ + title: string; + /** The type of the dataset, registered by other classes */ + type: string; + /** Optional reference to the data source */ + dataSource?: DataSource; +} + +/** + * Defines the structure of a dataset, including its type and reference to a data source. + * NOTE: For non-index pattern datasets we will append the data source ID to the front of + * the title of the dataset to ensure we do not have any conflicts. Many clusters could + * have similar titles and the data plugin assumes unique data set IDs. + * + * @example + * Example of a Dataset for an OpenSearch index pattern + * const logsIndexDataset: Dataset = { + * id: "2e1b1b80-9c4d-11ee-8c90-0242ac120001", + * title: "logs-*", + * type: "INDEX_PATTERN", + * timeFieldName: "@timestamp", + * dataSource: { + * id: "2e1b1b80-9c4d-11ee-8c90-0242ac120001", + * title: "Cluster1", + * type: "OpenSearch" + * } + * }; + * + * @example + * Example of a Dataset for an S3 table + * const ordersTableDataset: Dataset = { + * id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003::mys3.defaultDb.table1", + * title: "mys3.defaultDb.table1", + * type: "S3", + * timeFieldName: "order_date", + * dataSource: { + * id: "7d5c3e1c-ae5f-11ee-9c91-1357bd240003", + * title: "My S3 Connect", + * type: "S3_GLUE" + * }, + * }; + */ +export interface Dataset extends BaseDataset { + /** Optional name of the field used for time-based operations */ + timeFieldName?: string; + /** Optional language to default to from the language selector */ + language?: string; +} + +export interface DatasetField { + name: string; + type: string; + displayName?: string; + // TODO: osdFieldType? +} diff --git a/src/plugins/data/common/index.ts b/src/plugins/data/common/index.ts index a10855a498cd..ae3b3e9319da 100644 --- a/src/plugins/data/common/index.ts +++ b/src/plugins/data/common/index.ts @@ -31,7 +31,7 @@ export * from './constants'; export * from './opensearch_query'; export * from './data_frames'; -export * from './data_sets'; +export * from './datasets'; export * from './field_formats'; export * from './field_mapping'; export * from './index_patterns'; diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index 3d0dbe15dab7..ccda27870313 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts @@ -122,6 +122,7 @@ export class IndexPatternsService { this.savedObjectsCache = await Promise.all( this.savedObjectsCache.map(async (obj) => { + // TODO: This behaviour will cause the index pattern title to be resolved differently depending on how its fetched since the get method in this service will not append the datasource title if (obj.type === 'index-pattern') { const result = { ...obj }; result.attributes.title = await getIndexPatternTitle( diff --git a/src/plugins/data/common/query/types.ts b/src/plugins/data/common/query/types.ts index b80dd3c64840..7743c9cd346d 100644 --- a/src/plugins/data/common/query/types.ts +++ b/src/plugins/data/common/query/types.ts @@ -9,6 +9,8 @@ * GitHub history for details. */ +import { Dataset } from '../types'; + /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -34,4 +36,5 @@ export * from './timefilter/types'; export type Query = { query: string | { [key: string]: any }; language: string; + dataset?: Dataset; }; diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index e6ce014a7835..c95e54ffd35d 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -94,7 +94,6 @@ import { IDataFrameResponse, convertResult, createDataFrame, - getRawQueryString, } from '../../data_frames'; import { IOpenSearchSearchRequest, IOpenSearchSearchResponse, ISearchOptions } from '../..'; import { IOpenSearchDashboardsSearchRequest, IOpenSearchDashboardsSearchResponse } from '../types'; @@ -148,7 +147,7 @@ export interface SearchSourceDependencies extends FetchHandlers { ) => Promise; df: { get: () => IDataFrame | undefined; - set: (dataFrame: IDataFrame) => Promise; + set: (dataFrame: IDataFrame) => void; clear: () => void; }; } @@ -320,16 +319,9 @@ export class SearchSource { * @return {undefined|IDataFrame} */ async createDataFrame(searchRequest: SearchRequest) { - const rawQueryString = this.getRawQueryStringFromRequest(searchRequest); const dataFrame = createDataFrame({ name: searchRequest.index.title || searchRequest.index, fields: [], - ...(rawQueryString && { - meta: { - queryConfig: { qs: rawQueryString }, - ...(searchRequest.dataSourceId && { dataSource: searchRequest.dataSourceId }), - }, - }), }); await this.setDataFrame(dataFrame); return this.getDataFrame(); @@ -483,10 +475,6 @@ export class SearchSource { return request.body!.query.hasOwnProperty('type') && request.body!.query.type === 'unsupported'; } - private getRawQueryStringFromRequest(request: SearchRequest): string | undefined { - return getRawQueryString({ params: request }); - } - /** * Called by requests of this search source when they are started * @param options diff --git a/src/plugins/data/common/types.ts b/src/plugins/data/common/types.ts index 1670fbf72d5d..eb8b6500b6fa 100644 --- a/src/plugins/data/common/types.ts +++ b/src/plugins/data/common/types.ts @@ -29,13 +29,14 @@ */ import { DataFrameAggConfig, IDataFrame } from './data_frames'; +import { Query } from './query'; import { BucketAggType, MetricAggType } from './search'; export * from './query/types'; export * from './osd_field_types/types'; export * from './index_patterns/types'; export * from './data_frames/types'; -export * from './data_sets/types'; +export * from './datasets/types'; /** * If a service is being shared on both the client and the server, and @@ -50,12 +51,12 @@ export * from './data_sets/types'; export type GetConfigFn = (key: string, defaultOverride?: T) => T; export type GetDataFrameFn = () => IDataFrame | undefined; export type GetDataFrameAggQsFn = ({ - qs, + query, aggConfig, timeField, timeFilter, }: { - qs: string; + query: Query; aggConfig: DataFrameAggConfig; timeField: any; timeFilter: any; diff --git a/src/plugins/data/public/antlr/dql/code_completion.ts b/src/plugins/data/public/antlr/dql/code_completion.ts index 076fae33b9a2..6a10a519abaf 100644 --- a/src/plugins/data/public/antlr/dql/code_completion.ts +++ b/src/plugins/data/public/antlr/dql/code_completion.ts @@ -13,7 +13,7 @@ import { getTokenPosition } from '../shared/cursor'; import { IndexPattern, IndexPatternField } from '../../index_patterns'; import { QuerySuggestionGetFnArgs } from '../../autocomplete'; import { DQLParserVisitor } from './.generated/DQLParserVisitor'; -import { getUiService } from '../../services'; +import { getQueryService } from '../../services'; const findCursorIndex = ( tokenStream: TokenStream, @@ -132,7 +132,10 @@ export const getSuggestions = async ({ if ( !services || !services.appName || - !getUiService().Settings.supportsEnhancementsEnabled(services.appName) || + // TODO: might need to get language then pass here paul needs this to prevent this failing on other pages + // !getQueryService() + // .queryString.getLanguageService() + // .supportsEnhancementsEnabled(services.appName) || !indexPattern ) { return []; diff --git a/src/plugins/data/public/antlr/opensearch_sql/code_completion.ts b/src/plugins/data/public/antlr/opensearch_sql/code_completion.ts index d9aeedf727cf..bfd0d9d2da9c 100644 --- a/src/plugins/data/public/antlr/opensearch_sql/code_completion.ts +++ b/src/plugins/data/public/antlr/opensearch_sql/code_completion.ts @@ -47,7 +47,7 @@ export const getSuggestions = async ({ services, }: QuerySuggestionGetFnArgs): Promise => { const { api } = services.uiSettings; - const dataSetManager = services.data.query.dataSetManager; + const queryString = services.data.query.queryString; const { lineNumber, column } = position || {}; const suggestions = getOpenSearchSqlAutoCompleteSuggestions(query, { line: lineNumber || selectionStart, @@ -60,7 +60,7 @@ export const getSuggestions = async ({ // Fetch columns and values if (suggestions.suggestColumns?.tables?.length) { const tableNames = suggestions.suggestColumns.tables.map((table) => table.name); - const schemas = await fetchTableSchemas(tableNames, api, dataSetManager); + const schemas = await fetchTableSchemas(tableNames, api, queryString); (schemas as IDataFrameResponse[]).forEach((schema: IDataFrameResponse) => { if ('body' in schema && schema.body && 'fields' in schema.body) { diff --git a/src/plugins/data/public/antlr/shared/utils.test.ts b/src/plugins/data/public/antlr/shared/utils.test.ts index f255542a0184..c9f53cb3de0a 100644 --- a/src/plugins/data/public/antlr/shared/utils.test.ts +++ b/src/plugins/data/public/antlr/shared/utils.test.ts @@ -5,20 +5,20 @@ import { of } from 'rxjs'; import { fetchData } from './utils'; -import { DataSetManager } from '../../query'; +import { QueryStringManager } from '../../query'; describe('fetchData', () => { it('should fetch data using the dataSourceRequestHandler', async () => { const mockTables = ['table1', 'table2']; + const mockQuery = { + language: 'kuery', + dataset: { id: 'db', title: 'db', dataSource: { id: 'testId', title: 'testTitle' } }, + }; const mockQueryFormatter = jest.fn((table, dataSourceId, title) => ({ - query: { qs: `formatted ${table}`, format: 'jdbc' }, - df: { - meta: { - queryConfig: { - dataSourceId, - title, - }, - }, + query: { + query: `formatted ${table}`, + format: 'jdbc', + ...mockQuery, }, })); const mockApi = { @@ -26,18 +26,16 @@ describe('fetchData', () => { fetch: jest.fn().mockResolvedValue('fetchedData'), }, }; - const mockDataSetManager: Partial = { - getUpdates$: jest - .fn() - .mockReturnValue(of({ dataSourceRef: { id: 'testId', name: 'testTitle' } })), - getDataSet: jest.fn().mockReturnValue({ dataSourceRef: { id: 'testId', name: 'testTitle' } }), + const mockQueryString: Partial = { + getUpdates$: jest.fn().mockReturnValue(of(mockQuery)), + getQuery: jest.fn().mockReturnValue(mockQuery), }; const result = await fetchData( mockTables, mockQueryFormatter, mockApi, - mockDataSetManager as DataSetManager + mockQueryString as QueryStringManager ); expect(result).toEqual(['fetchedData', 'fetchedData']); expect(mockQueryFormatter).toHaveBeenCalledWith('table1', 'testId', 'testTitle'); @@ -46,29 +44,28 @@ describe('fetchData', () => { it('should fetch data using the defaultRequestHandler', async () => { const mockTables = ['table1', 'table2']; + const mockQuery = { + language: 'kuery', + dataset: { id: 'db', title: 'db', dataSource: { id: 'testId', title: 'testTitle' } }, + }; const mockQueryFormatter = jest.fn((table) => ({ - query: { qs: `formatted ${table}`, format: 'jdbc' }, - df: { - meta: { - queryConfig: {}, - }, - }, + query: { qs: `formatted ${table}`, format: 'jdbc', ...mockQuery }, })); const mockApi = { http: { fetch: jest.fn().mockResolvedValue('fetchedData'), }, }; - const mockDataSetManager: Partial = { + const mockQueryString: Partial = { getUpdates$: jest.fn().mockReturnValue(of(undefined)), - getDataSet: jest.fn().mockReturnValue(undefined), + getQuery: jest.fn().mockReturnValue(undefined), }; const result = await fetchData( mockTables, mockQueryFormatter, mockApi, - mockDataSetManager as DataSetManager + mockQueryString as QueryStringManager ); expect(result).toEqual(['fetchedData', 'fetchedData']); expect(mockQueryFormatter).toHaveBeenCalledWith('table1'); diff --git a/src/plugins/data/public/antlr/shared/utils.ts b/src/plugins/data/public/antlr/shared/utils.ts index 50897a408523..7ae9dd18940b 100644 --- a/src/plugins/data/public/antlr/shared/utils.ts +++ b/src/plugins/data/public/antlr/shared/utils.ts @@ -5,7 +5,7 @@ import { from } from 'rxjs'; import { distinctUntilChanged, startWith, switchMap } from 'rxjs/operators'; -import { DataSetManager } from '../../query'; +import { QueryStringContract } from '../../query'; export interface IDataSourceRequestHandlerParams { dataSourceId: string; @@ -14,22 +14,22 @@ export interface IDataSourceRequestHandlerParams { // Function to get raw suggestion data export const getRawSuggestionData$ = ( - dataSetManager: DataSetManager, + queryString: QueryStringContract, dataSourceRequestHandler: ({ dataSourceId, title, }: IDataSourceRequestHandlerParams) => Promise, defaultRequestHandler: () => Promise ) => - dataSetManager.getUpdates$().pipe( - startWith(dataSetManager.getDataSet()), + queryString.getUpdates$().pipe( + startWith(queryString.getQuery()), distinctUntilChanged(), - switchMap((dataSet) => { - if (!dataSet) { + switchMap((query) => { + if (!query) { return from(defaultRequestHandler()); } - const dataSourceId = dataSet?.dataSourceRef?.id; - const title = dataSet?.dataSourceRef?.name; + const dataSourceId = query.dataset?.dataSource?.id; + const title = query.dataset?.dataSource?.title; return from(dataSourceRequestHandler({ dataSourceId, title })); }) ); @@ -52,11 +52,11 @@ export const fetchData = ( tables: string[], queryFormatter: (table: string, dataSourceId?: string, title?: string) => any, api: any, - dataSetManager: DataSetManager + queryString: QueryStringContract ) => { return new Promise((resolve, reject) => { getRawSuggestionData$( - dataSetManager, + queryString, ({ dataSourceId, title }) => { const requests = tables.map(async (table) => { const body = JSON.stringify(queryFormatter(table, dataSourceId, title)); @@ -82,11 +82,11 @@ export const fetchData = ( }; // Specific fetch function for table schemas -export const fetchTableSchemas = (tables: string[], api: any, dataSetManager: DataSetManager) => { +export const fetchTableSchemas = (tables: string[], api: any, queryString: QueryStringContract) => { return fetchData( tables, (table, dataSourceId, title) => ({ - query: { qs: `DESCRIBE TABLES LIKE ${table}`, format: 'jdbc' }, + query: { query: `DESCRIBE TABLES LIKE ${table}`, format: 'jdbc' }, df: { meta: { queryConfig: { @@ -97,6 +97,6 @@ export const fetchTableSchemas = (tables: string[], api: any, dataSetManager: Da }, }), api, - dataSetManager + queryString ); }; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index e8a64a0bcb6a..f2696e824112 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -62,6 +62,7 @@ import { } from '../common'; import { FilterLabel } from './ui'; +export { createEditor, DefaultInput, DQLBody, SingleLineInput } from './ui'; import { generateFilters, @@ -445,10 +446,7 @@ export { QueryEditorTopRow, // for BWC, keeping the old name IUiStart as DataPublicPluginStartUi, - DataSetNavigator, - setAsyncSessionId, - getAsyncSessionId, - setAsyncSessionIdByObj, + useQueryStringManager, } from './ui'; /** @@ -465,8 +463,14 @@ export { QueryState, getDefaultQuery, FilterManager, - DataSetManager, - DataSetContract, + QueryStringContract, + QueryStringManager, + DatasetTypeConfig, + DatasetService, + DatasetServiceContract, + LanguageConfig, + LanguageService, + LanguageServiceContract, SavedQuery, SavedQueryService, SavedQueryTimeFilter, diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 958ac99e93db..2b5f30981c12 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -50,8 +50,8 @@ const autocompleteStartMock: jest.Mocked = { hasQuerySuggestions: jest.fn(), }; -const createSetupContract = (): Setup => { - const querySetupMock = queryServiceMock.createSetupContract(); +const createSetupContract = (isEnhancementsEnabled: boolean = false): Setup => { + const querySetupMock = queryServiceMock.createSetupContract(isEnhancementsEnabled); return { autocomplete: automcompleteSetupMock, search: searchServiceMock.createSetupContract(), @@ -62,7 +62,7 @@ const createSetupContract = (): Setup => { }; const createStartContract = (isEnhancementsEnabled: boolean = false): Start => { - const queryStartMock = queryServiceMock.createStartContract(); + const queryStartMock = queryServiceMock.createStartContract(isEnhancementsEnabled); return { actions: { createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']), @@ -72,10 +72,7 @@ const createStartContract = (isEnhancementsEnabled: boolean = false): Start => { search: searchServiceMock.createStartContract(), fieldFormats: fieldFormatsServiceMock.createStartContract(), query: queryStartMock, - ui: uiServiceMock.createStartContract( - isEnhancementsEnabled, - searchServiceMock.createStartContract() - ), + ui: uiServiceMock.createStartContract(), indexPatterns: ({ find: jest.fn((search) => [{ id: search, title: search }]), createField: jest.fn(() => {}), diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 09bdd96d58e2..916909e25acb 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -134,9 +134,15 @@ export class DataPublicPlugin expressions.registerFunction(opensearchaggs); expressions.registerFunction(indexPatternLoad); + const searchService = this.searchService.setup(core, { + usageCollection, + expressions, + }); + const queryService = this.queryService.setup({ uiSettings: core.uiSettings, storage: this.storage, + defaultSearchInterceptor: searchService.getDefaultSearchInterceptor(), }); uiActions.registerAction( @@ -157,13 +163,6 @@ export class DataPublicPlugin })) ); - const searchService = this.searchService.setup(core, { - usageCollection, - expressions, - }); - - const uiService = this.uiService.setup(core, {}); - const ac = this.autocomplete.setup(core); ac.addQuerySuggestionProvider('SQL', getSQLSuggestions); ac.addQuerySuggestionProvider('kuery', getDQLSuggestions); @@ -176,7 +175,8 @@ export class DataPublicPlugin query: queryService, __enhance: (enhancements: DataPublicPluginEnhancements) => { if (enhancements.search) searchService.__enhance(enhancements.search); - if (enhancements.ui) uiService.__enhance(enhancements.ui); + if (enhancements.editor) + queryService.queryString.getLanguageService().__enhance(enhancements.editor); }, }; } diff --git a/src/plugins/data/public/query/dataset_manager/dataset_manager.mock.ts b/src/plugins/data/public/query/dataset_manager/dataset_manager.mock.ts deleted file mode 100644 index 93dcdfb22b82..000000000000 --- a/src/plugins/data/public/query/dataset_manager/dataset_manager.mock.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { DataSetContract } from '.'; - -const createSetupContractMock = () => { - const dataSetManagerMock: jest.Mocked = { - init: jest.fn(), - getDataSet: jest.fn(), - setDataSet: jest.fn(), - getUpdates$: jest.fn(), - getDefaultDataSet: jest.fn(), - fetchDefaultDataSet: jest.fn(), - initWithIndexPattern: jest.fn(), - }; - return dataSetManagerMock; -}; - -export const dataSetManagerMock = { - createSetupContract: createSetupContractMock, - createStartContract: createSetupContractMock, -}; diff --git a/src/plugins/data/public/query/dataset_manager/dataset_manager.test.ts b/src/plugins/data/public/query/dataset_manager/dataset_manager.test.ts deleted file mode 100644 index 8f87f063d9be..000000000000 --- a/src/plugins/data/public/query/dataset_manager/dataset_manager.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { DataSetManager } from './dataset_manager'; -import { coreMock } from '../../../../../core/public/mocks'; -import { SimpleDataSet } from '../../../common'; -describe('DataSetManager', () => { - let service: DataSetManager; - - beforeEach(() => { - const uiSettingsMock = coreMock.createSetup().uiSettings; - uiSettingsMock.get.mockReturnValue(true); - service = new DataSetManager(uiSettingsMock); - }); - - test('getUpdates$ is a cold emits only after dataset changes', () => { - const obs$ = service.getUpdates$(); - const emittedValues: SimpleDataSet[] = []; - obs$.subscribe((v) => { - emittedValues.push(v!); - }); - expect(emittedValues).toHaveLength(0); - expect(emittedValues[0]).toEqual(undefined); - - const newDataSet: SimpleDataSet = { id: 'test_dataset', title: 'Test Dataset' }; - service.setDataSet(newDataSet); - expect(emittedValues).toHaveLength(1); - expect(emittedValues[0]).toEqual(newDataSet); - - service.setDataSet({ ...newDataSet }); - expect(emittedValues).toHaveLength(2); - }); -}); diff --git a/src/plugins/data/public/query/dataset_manager/dataset_manager.ts b/src/plugins/data/public/query/dataset_manager/dataset_manager.ts deleted file mode 100644 index 3aff5b927597..000000000000 --- a/src/plugins/data/public/query/dataset_manager/dataset_manager.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { BehaviorSubject } from 'rxjs'; -import { CoreStart } from 'opensearch-dashboards/public'; -import { skip } from 'rxjs/operators'; -import { - IndexPattern, - SIMPLE_DATA_SET_TYPES, - SimpleDataSet, - SimpleDataSource, - UI_SETTINGS, -} from '../../../common'; -import { IndexPatternsContract } from '../../index_patterns'; - -export class DataSetManager { - private dataSet$: BehaviorSubject; - private indexPatterns?: IndexPatternsContract; - private defaultDataSet?: SimpleDataSet; - - constructor(private readonly uiSettings: CoreStart['uiSettings']) { - this.dataSet$ = new BehaviorSubject(undefined); - } - - public init = async (indexPatterns: IndexPatternsContract) => { - if (!this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED)) return; - this.indexPatterns = indexPatterns; - this.defaultDataSet = await this.fetchDefaultDataSet(); - }; - - public initWithIndexPattern = (indexPattern: IndexPattern | null) => { - if (!this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED)) return; - if (!indexPattern || !indexPattern.id) { - return undefined; - } - - this.defaultDataSet = { - id: indexPattern.id, - title: indexPattern.title, - type: SIMPLE_DATA_SET_TYPES.INDEX_PATTERN, - timeFieldName: indexPattern.timeFieldName, - fields: indexPattern.fields, - ...(indexPattern.dataSourceRef - ? { - dataSourceRef: { - id: indexPattern.dataSourceRef?.id, - name: indexPattern.dataSourceRef?.name, - type: indexPattern.dataSourceRef?.type, - } as SimpleDataSource, - } - : {}), - }; - }; - - public getUpdates$ = () => { - return this.dataSet$.asObservable().pipe(skip(1)); - }; - - public getDataSet = () => { - return this.dataSet$.getValue(); - }; - - /** - * Updates the query. - * @param {Query} query - */ - public setDataSet = (dataSet: SimpleDataSet | undefined) => { - if (!this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED)) return; - - // if (dataSet) { - // const { fields, ...dataSetWithoutFields } = dataSet; - // this.dataSet$.next(dataSetWithoutFields); - // } else { - // this.dataSet$.next(undefined); - // } - this.dataSet$.next(dataSet); - }; - - public getDefaultDataSet = () => { - return this.defaultDataSet; - }; - - public fetchDefaultDataSet = async (): Promise => { - const defaultIndexPatternId = this.uiSettings.get('defaultIndex'); - if (!defaultIndexPatternId) { - return undefined; - } - - const indexPattern = await this.indexPatterns?.get(defaultIndexPatternId); - if (!indexPattern || !indexPattern.id) { - return undefined; - } - - return { - id: indexPattern.id, - title: indexPattern.title, - type: SIMPLE_DATA_SET_TYPES.INDEX_PATTERN, - timeFieldName: indexPattern.timeFieldName, - ...(indexPattern.dataSourceRef - ? { - dataSourceRef: { - id: indexPattern.dataSourceRef?.id, - name: indexPattern.dataSourceRef?.name, - type: indexPattern.dataSourceRef?.type, - } as SimpleDataSource, - } - : {}), - }; - }; -} - -export type DataSetContract = PublicMethodsOf; diff --git a/src/plugins/data/public/query/index.tsx b/src/plugins/data/public/query/index.tsx index 42c6349bcc89..d5dda197917a 100644 --- a/src/plugins/data/public/query/index.tsx +++ b/src/plugins/data/public/query/index.tsx @@ -29,10 +29,10 @@ */ export * from './lib'; - +export * from './types'; export * from './query_service'; export * from './filter_manager'; -export * from './dataset_manager'; +export * from './query_string'; export * from './timefilter'; export * from './saved_query'; export * from './persisted_log'; diff --git a/src/plugins/data/public/query/mocks.ts b/src/plugins/data/public/query/mocks.ts index 87bd2edb49bc..f6f1713e554a 100644 --- a/src/plugins/data/public/query/mocks.ts +++ b/src/plugins/data/public/query/mocks.ts @@ -33,31 +33,28 @@ import { QueryService, QuerySetup, QueryStart } from '.'; import { timefilterServiceMock } from './timefilter/timefilter_service.mock'; import { createFilterManagerMock } from './filter_manager/filter_manager.mock'; import { queryStringManagerMock } from './query_string/query_string_manager.mock'; -import { dataSetManagerMock } from './dataset_manager/dataset_manager.mock'; type QueryServiceClientContract = PublicMethodsOf; -const createSetupContractMock = () => { +const createSetupContractMock = (isEnhancementsEnabled: boolean = false) => { const setupContract: jest.Mocked = { filterManager: createFilterManagerMock(), timefilter: timefilterServiceMock.createSetupContract(), - queryString: queryStringManagerMock.createSetupContract(), - dataSetManager: dataSetManagerMock.createSetupContract(), + queryString: queryStringManagerMock.createSetupContract(isEnhancementsEnabled), state$: new Observable(), }; return setupContract; }; -const createStartContractMock = () => { +const createStartContractMock = (isEnhancementsEnabled: boolean = false) => { const startContract: jest.Mocked = { addToQueryLog: jest.fn(), filterManager: createFilterManagerMock(), - queryString: queryStringManagerMock.createStartContract(), + queryString: queryStringManagerMock.createStartContract(isEnhancementsEnabled), savedQueries: jest.fn() as any, state$: new Observable(), timefilter: timefilterServiceMock.createStartContract(), - dataSetManager: dataSetManagerMock.createStartContract(), getOpenSearchQuery: jest.fn(), }; diff --git a/src/plugins/data/public/query/query_service.ts b/src/plugins/data/public/query/query_service.ts index 17a7773567f3..dba19cca19b0 100644 --- a/src/plugins/data/public/query/query_service.ts +++ b/src/plugins/data/public/query/query_service.ts @@ -29,49 +29,39 @@ */ import { share } from 'rxjs/operators'; -import { IUiSettingsClient, SavedObjectsClientContract } from 'src/core/public'; import { FilterManager } from './filter_manager'; import { createAddToQueryLog } from './lib'; import { TimefilterService, TimefilterSetup } from './timefilter'; import { createSavedQueryService } from './saved_query/saved_query_service'; import { createQueryStateObservable } from './state_sync/create_global_query_observable'; import { QueryStringManager, QueryStringContract } from './query_string'; -import { DataSetContract, DataSetManager } from './dataset_manager'; -import { - buildOpenSearchQuery, - DataStorage, - getOpenSearchQueryConfig, - IndexPatternsService, -} from '../../common'; +import { buildOpenSearchQuery, getOpenSearchQueryConfig } from '../../common'; import { getUiSettings } from '../services'; import { IndexPattern } from '..'; +import { + IQuerySetup, + IQueryStart, + QueryServiceSetupDependencies, + QueryServiceStartDependencies, +} from './types'; /** * Query Service * @internal */ -interface QueryServiceSetupDependencies { - storage: DataStorage; - uiSettings: IUiSettingsClient; -} - -interface QueryServiceStartDependencies { - savedObjectsClient: SavedObjectsClientContract; - storage: DataStorage; - uiSettings: IUiSettingsClient; - indexPatterns: IndexPatternsService; -} - export class QueryService { filterManager!: FilterManager; timefilter!: TimefilterSetup; queryStringManager!: QueryStringContract; - dataSetManager!: DataSetContract; state$!: ReturnType; - public setup({ storage, uiSettings }: QueryServiceSetupDependencies) { + public setup({ + storage, + uiSettings, + defaultSearchInterceptor, + }: QueryServiceSetupDependencies): IQuerySetup { this.filterManager = new FilterManager(uiSettings); const timefilterService = new TimefilterService(); @@ -80,21 +70,18 @@ export class QueryService { storage, }); - this.queryStringManager = new QueryStringManager(storage, uiSettings); - this.dataSetManager = new DataSetManager(uiSettings); + this.queryStringManager = new QueryStringManager(storage, uiSettings, defaultSearchInterceptor); this.state$ = createQueryStateObservable({ filterManager: this.filterManager, timefilter: this.timefilter, queryString: this.queryStringManager, - dataSetManager: this.dataSetManager, }).pipe(share()); return { filterManager: this.filterManager, timefilter: this.timefilter, queryString: this.queryStringManager, - dataSetManager: this.dataSetManager, state$: this.state$, }; } @@ -104,8 +91,8 @@ export class QueryService { storage, uiSettings, indexPatterns, - }: QueryServiceStartDependencies) { - this.dataSetManager.init(indexPatterns); + }: QueryServiceStartDependencies): IQueryStart { + this.queryStringManager.getDatasetService().init(indexPatterns); return { addToQueryLog: createAddToQueryLog({ storage, @@ -113,7 +100,6 @@ export class QueryService { }), filterManager: this.filterManager, queryString: this.queryStringManager, - dataSetManager: this.dataSetManager, savedQueries: createSavedQueryService(savedObjectsClient), state$: this.state$, timefilter: this.timefilter, diff --git a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.mock.ts b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.mock.ts new file mode 100644 index 000000000000..ecf7c74410ca --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.mock.ts @@ -0,0 +1,50 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { DatasetServiceContract } from './dataset_service'; +import { Dataset, DEFAULT_DATA } from '../../../../common'; +import { DatasetTypeConfig } from './types'; + +const createSetupDatasetServiceMock = (): jest.Mocked => { + const mockIndexPatternType: DatasetTypeConfig = { + id: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + title: 'Index Patterns', + meta: { + icon: { type: 'indexPatternApp' }, + tooltip: 'OpenSearch Index Patterns', + }, + toDataset: jest.fn(), + fetch: jest.fn(), + fetchFields: jest.fn(), + supportedLanguages: jest.fn().mockReturnValue(['DQL', 'Lucene', 'PPL', 'SQL']), + }; + + const defaultDataset: Dataset = { + id: 'default-index-pattern', + title: 'Default Index Pattern', + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + timeFieldName: '@timestamp', + dataSource: { + id: 'mock-data-source-id', + title: 'Default Data Source', + type: DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, + }, + }; + + return { + init: jest.fn(), + registerType: jest.fn(), + getType: jest.fn().mockReturnValue(mockIndexPatternType), + getTypes: jest.fn().mockReturnValue([mockIndexPatternType]), + getDefault: jest.fn().mockReturnValue(defaultDataset), + cacheDataset: jest.fn(), + fetchOptions: jest.fn(), + }; +}; + +export const datasetServiceMock = { + createSetupContract: createSetupDatasetServiceMock, + createStartContract: createSetupDatasetServiceMock, +}; diff --git a/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts new file mode 100644 index 000000000000..ee4ab700e847 --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/dataset_service.ts @@ -0,0 +1,124 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { CoreStart, SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { + Dataset, + DataStructure, + IndexPatternSpec, + DEFAULT_DATA, + IFieldType, + UI_SETTINGS, +} from '../../../../common'; +import { DatasetTypeConfig } from './types'; +import { indexPatternTypeConfig, indexTypeConfig } from './lib'; +import { IndexPatternsContract } from '../../../index_patterns'; + +export class DatasetService { + private indexPatterns?: IndexPatternsContract; + private defaultDataset?: Dataset; + private typesRegistry: Map = new Map(); + + constructor(private readonly uiSettings: CoreStart['uiSettings']) { + if (this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED)) { + this.registerDefaultTypes(); + } + } + + /** + * Registers default handlers for index patterns and indices. + */ + private registerDefaultTypes() { + this.registerType(indexPatternTypeConfig); + this.registerType(indexTypeConfig); + } + + public async init(indexPatterns: IndexPatternsContract): Promise { + this.indexPatterns = indexPatterns; + this.defaultDataset = await this.fetchDefaultDataset(); + } + + public registerType(handlerConfig: DatasetTypeConfig): void { + this.typesRegistry.set(handlerConfig.id, handlerConfig); + } + + public getType(type: string): DatasetTypeConfig | undefined { + return this.typesRegistry.get(type); + } + + public getTypes(): DatasetTypeConfig[] { + return Array.from(this.typesRegistry.values()); + } + + public getDefault(): Dataset | undefined { + return this.defaultDataset; + } + + public async cacheDataset(dataset: Dataset): Promise { + const type = this.getType(dataset.type); + if (dataset) { + const spec = { + id: dataset.id, + title: dataset.title, + timeFieldName: { + name: dataset.timeFieldName, + type: 'date', + } as Partial, + fields: await type?.fetchFields(dataset), + dataSourceRef: dataset.dataSource + ? { + id: dataset.dataSource.id!, + name: dataset.dataSource.title, + type: dataset.dataSource.type, + } + : undefined, + } as IndexPatternSpec; + const temporaryIndexPattern = await this.indexPatterns?.create(spec); + if (temporaryIndexPattern) { + this.indexPatterns?.saveToCache(dataset.id, temporaryIndexPattern); + } + } + } + + public fetchOptions( + savedObjects: SavedObjectsClientContract, + path: DataStructure[], + dataType: string + ): Promise { + const type = this.typesRegistry.get(dataType); + if (!type) { + throw new Error(`No handler found for type: ${path[0]}`); + } + return type.fetch(savedObjects, path); + } + + private async fetchDefaultDataset(): Promise { + const defaultIndexPatternId = this.uiSettings.get('defaultIndex'); + if (!defaultIndexPatternId) { + return undefined; + } + + const indexPattern = await this.indexPatterns?.get(defaultIndexPatternId); + if (!indexPattern || !indexPattern.id) { + return undefined; + } + + const dataType = this.typesRegistry.get(DEFAULT_DATA.SET_TYPES.INDEX_PATTERN); + if (dataType) { + const dataset = dataType.toDataset([ + { + id: indexPattern.id, + title: indexPattern.title, + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + }, + ]); + return { ...dataset, timeFieldName: indexPattern.timeFieldName }; + } + + return undefined; + } +} + +export type DatasetServiceContract = PublicMethodsOf; diff --git a/src/plugins/data/public/query/query_string/dataset_service/index.ts b/src/plugins/data/public/query/query_string/dataset_service/index.ts new file mode 100644 index 000000000000..8becfe4126ac --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './types'; +export { DatasetServiceContract, DatasetService } from './dataset_service'; diff --git a/src/plugins/data/public/query/dataset_manager/index.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index.ts similarity index 54% rename from src/plugins/data/public/query/dataset_manager/index.ts rename to src/plugins/data/public/query/query_string/dataset_service/lib/index.ts index 8a9a39b81127..68ba7d2d09b8 100644 --- a/src/plugins/data/public/query/dataset_manager/index.ts +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index.ts @@ -3,4 +3,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -export { DataSetContract, DataSetManager } from './dataset_manager'; +export * from './index_type'; +export * from './index_pattern_type'; diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts new file mode 100644 index 000000000000..71710adc7b50 --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_pattern_type.ts @@ -0,0 +1,125 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { DataSourceAttributes } from '../../../../../../data_source/common/data_sources'; +import { + DEFAULT_DATA, + DataStructure, + DatasetField, + Dataset, + IIndexPattern, + DATA_STRUCTURE_META_TYPES, +} from '../../../../../common'; +import { DatasetTypeConfig } from '../types'; +import { getIndexPatterns } from '../../../../services'; + +export const indexPatternTypeConfig: DatasetTypeConfig = { + id: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + title: 'Index Patterns', + meta: { + icon: { type: 'indexPatternApp' }, + tooltip: 'OpenSearch Index Patterns', + }, + + toDataset: (path) => { + const pattern = path[path.length - 1]; + return { + id: pattern.id, + title: pattern.title, + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + dataSource: pattern.parent + ? { + id: pattern.parent.id, + title: pattern.parent.title, + type: pattern.parent.type, + } + : undefined, + } as Dataset; + }, + + fetch: async (savedObjects, path) => { + const dataStructure = path[path.length - 1]; + const indexPatterns = await fetchIndexPatterns(savedObjects); + return { + ...dataStructure, + columnHeader: 'Index patterns', + children: indexPatterns, + hasNext: false, + }; + }, + + fetchFields: async (dataset: Dataset): Promise => { + const indexPattern = await getIndexPatterns().get(dataset.id); + return indexPattern.fields.map((field: any) => ({ + name: field.name, + type: field.type, + })); + }, + + supportedLanguages: (dataset): string[] => { + if (dataset.dataSource?.type === 'OpenSearch Serverless') { + return ['DQL', 'Lucene']; + } + return ['DQL', 'Lucene', 'PPL', 'SQL']; + }, +}; + +const fetchIndexPatterns = async (client: SavedObjectsClientContract): Promise => { + const resp = await client.find({ + type: 'index-pattern', + fields: ['title', 'timeFieldName', 'references'], + search: `*`, + searchFields: ['title'], + perPage: 100, + }); + + // Get all unique data source ids + const datasourceIds = Array.from( + new Set( + resp.savedObjects + .filter((savedObject) => savedObject.references.length > 0) + .map((savedObject) => savedObject.references.find((ref) => ref.type === 'data-source')?.id) + .filter(Boolean) + ) + ) as string[]; + + const dataSourceMap: Record = {}; + if (datasourceIds.length > 0) { + const dataSourceResp = await client.bulkGet( + datasourceIds.map((id) => ({ id, type: 'data-source' })) + ); + + dataSourceResp.savedObjects.forEach((savedObject) => { + dataSourceMap[savedObject.id] = savedObject.attributes; + }); + } + + return resp.savedObjects.map( + (savedObject): DataStructure => { + const dataSourceId = savedObject.references.find((ref) => ref.type === 'data-source')?.id; + const dataSource = dataSourceId ? dataSourceMap[dataSourceId] : undefined; + + const indexPatternDataStructure: DataStructure = { + id: savedObject.id, + title: savedObject.attributes.title, + type: DEFAULT_DATA.SET_TYPES.INDEX_PATTERN, + meta: { + type: DATA_STRUCTURE_META_TYPES.CUSTOM, + timeFieldName: savedObject.attributes.timeFieldName, + }, + }; + + if (dataSource) { + indexPatternDataStructure.parent = { + id: dataSourceId!, // Since we know it exists + title: dataSource.title, + type: dataSource.dataSourceEngineType ?? DEFAULT_DATA.SOURCE_TYPES.OPENSEARCH, + }; + } + return indexPatternDataStructure; + } + ); +}; diff --git a/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts new file mode 100644 index 000000000000..738e763c0508 --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/lib/index_type.ts @@ -0,0 +1,140 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { map } from 'rxjs/operators'; +import { DEFAULT_DATA, DataStructure, Dataset } from '../../../../../common'; +import { DatasetTypeConfig } from '../types'; +import { getSearchService, getIndexPatterns } from '../../../../services'; + +const INDEX_INFO = { + LOCAL_DATASOURCE: { + id: '', + title: 'Local Cluster', + type: 'DATA_SOURCE', + }, +}; + +export const indexTypeConfig: DatasetTypeConfig = { + id: DEFAULT_DATA.SET_TYPES.INDEX, + title: 'Indexes', + meta: { + icon: { type: 'logoOpenSearch' }, + tooltip: 'OpenSearch Indexes', + }, + + toDataset: (path) => { + const index = path[path.length - 1]; + const dataSource = path.find((ds) => ds.type === 'DATA_SOURCE'); + + return { + id: index.id, + title: index.title, + type: DEFAULT_DATA.SET_TYPES.INDEX, + dataSource: dataSource + ? { + id: dataSource.id, + title: dataSource.title, + type: dataSource.type, + } + : INDEX_INFO.LOCAL_DATASOURCE, + }; + }, + + fetch: async (savedObjects, path) => { + const dataStructure = path[path.length - 1]; + switch (dataStructure.type) { + case 'DATA_SOURCE': { + const indices = await fetchIndices(dataStructure); + return { + ...dataStructure, + hasNext: false, + columnHeader: 'Indexes', + children: indices.map((indexName) => ({ + id: `${dataStructure.id}::${indexName}`, + title: indexName, + type: 'INDEX', + })), + }; + } + + default: { + const dataSources = await fetchDataSources(savedObjects); + return { + ...dataStructure, + columnHeader: 'Cluster', + hasNext: true, + children: dataSources, + }; + } + } + }, + + fetchFields: async (dataset) => { + const fields = await getIndexPatterns().getFieldsForWildcard({ + pattern: dataset.title, + dataSourceId: dataset.dataSource?.id, + }); + return fields.map((field: any) => ({ + name: field.name, + type: field.type, + })); + }, + + supportedLanguages: (dataset: Dataset): string[] => { + return ['SQL', 'PPL']; + }, +}; + +const fetchDataSources = async (client: SavedObjectsClientContract) => { + const resp = await client.find({ + type: 'data-source', + perPage: 10000, + }); + const dataSources: DataStructure[] = [INDEX_INFO.LOCAL_DATASOURCE]; + return dataSources.concat( + resp.savedObjects.map((savedObject) => ({ + id: savedObject.id, + title: savedObject.attributes.title, + type: 'DATA_SOURCE', + })) + ); +}; + +const fetchIndices = async (dataStructure: DataStructure): Promise => { + const search = getSearchService(); + const buildSearchRequest = () => ({ + params: { + ignoreUnavailable: true, + expand_wildcards: 'all', + index: '*', + body: { + size: 0, + aggs: { + indices: { + terms: { + field: '_index', + size: 100, + }, + }, + }, + }, + }, + dataSourceId: dataStructure.id, + }); + + const searchResponseToArray = (response: any) => { + const { rawResponse } = response; + return rawResponse.aggregations + ? rawResponse.aggregations.indices.buckets.map((bucket: { key: any }) => bucket.key) + : []; + }; + + return search + .getDefaultSearchInterceptor() + .search(buildSearchRequest()) + .pipe(map(searchResponseToArray)) + .toPromise(); +}; diff --git a/src/plugins/data/public/query/query_string/dataset_service/types.ts b/src/plugins/data/public/query/query_string/dataset_service/types.ts new file mode 100644 index 000000000000..8d597694ac49 --- /dev/null +++ b/src/plugins/data/public/query/query_string/dataset_service/types.ts @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { EuiIconProps } from '@elastic/eui'; +import { Dataset, DatasetField, DataStructure } from '../../../../common'; + +/** + * Configuration for handling dataset operations. + */ +export interface DatasetTypeConfig { + /** Unique identifier for the dataset handler */ + id: string; + /** Human-readable title for the dataset type */ + title: string; + /** Metadata for UI representation */ + meta: { + /** Icon to represent the dataset type */ + icon: EuiIconProps; + /** Optional tooltip text */ + tooltip?: string; + }; + /** + * Converts a DataStructure to a Dataset. + * @param {DataStructure} dataStructure - The data structure to convert. + * @returns {Dataset} Dataset. + */ + toDataset: (path: DataStructure[]) => Dataset; + /** + * Fetches child options for a given DataStructure. + * @param {SavedObjectsClientContract} client - The saved objects client. + * @param {DataStructure} dataStructure - The parent DataStructure. + * @returns {Promise} A promise that resolves to a DatasetHandlerFetchResponse. + */ + fetch: (client: SavedObjectsClientContract, path: DataStructure[]) => Promise; + /** + * Fetches fields for the dataset. + * @returns {Promise} A promise that resolves to an array of DatasetFields. + */ + fetchFields: (dataset: Dataset) => Promise; + /** + * Retrieves the supported query languages for this dataset type. + * @returns {Promise} A promise that resolves to an array of supported language names. + */ + supportedLanguages: (dataset: Dataset) => string[]; +} diff --git a/src/plugins/data/public/query/query_string/index.ts b/src/plugins/data/public/query/query_string/index.ts index 21d250e3fbb1..9e5b584a5e2e 100644 --- a/src/plugins/data/public/query/query_string/index.ts +++ b/src/plugins/data/public/query/query_string/index.ts @@ -29,3 +29,10 @@ */ export { QueryStringContract, QueryStringManager } from './query_string_manager'; +export { DatasetServiceContract, DatasetService, DatasetTypeConfig } from './dataset_service'; +export { + LanguageServiceContract, + LanguageService, + LanguageConfig, + EditorEnhancements, +} from './language_service'; diff --git a/src/plugins/data/public/query/query_string/language_service/index.ts b/src/plugins/data/public/query/query_string/language_service/index.ts new file mode 100644 index 000000000000..79aea071de3f --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export * from './types'; +export { LanguageServiceContract, LanguageService } from './language_service'; diff --git a/src/plugins/data/public/query/query_string/language_service/language_service.mock.ts b/src/plugins/data/public/query/query_string/language_service/language_service.mock.ts new file mode 100644 index 000000000000..80b6aa478b00 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/language_service.mock.ts @@ -0,0 +1,69 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { LanguageServiceContract } from './language_service'; +import { LanguageConfig } from './types'; + +const createSetupLanguageServiceMock = (): jest.Mocked => { + const languages = new Map(); + + const mockDQLLanguage: LanguageConfig = { + id: 'kuery', + title: 'DQL', + search: {} as any, + getQueryString: jest.fn(), + editor: {} as any, + fields: { + filterable: true, + visualizable: true, + }, + showDocLinks: true, + editorSupportedAppNames: ['discover'], + }; + + const mockLuceneLanguage: LanguageConfig = { + id: 'lucene', + title: 'Lucene', + search: {} as any, + getQueryString: jest.fn(), + editor: {} as any, + fields: { + filterable: true, + visualizable: true, + }, + showDocLinks: true, + editorSupportedAppNames: ['discover'], + }; + + languages.set(mockDQLLanguage.id, mockDQLLanguage); + languages.set(mockLuceneLanguage.id, mockLuceneLanguage); + + return { + __enhance: jest.fn(), + registerLanguage: jest.fn(), + getLanguage: jest.fn((id: string) => languages.get(id)), + getLanguages: jest.fn(() => Array.from(languages.values())), + getDefaultLanguage: jest.fn(() => languages.get('kuery') || languages.values().next().value), + getQueryEditorExtensionMap: jest.fn().mockReturnValue({}), + resetUserQuery: jest.fn(), + getUserQueryLanguageBlocklist: jest.fn().mockReturnValue([]), + setUserQueryLanguageBlocklist: jest.fn().mockReturnValue(true), + getUserQueryLanguage: jest.fn().mockReturnValue('kuery'), + setUserQueryLanguage: jest.fn().mockReturnValue(true), + getUserQueryString: jest.fn().mockReturnValue(''), + setUserQueryString: jest.fn().mockReturnValue(true), + getUiOverrides: jest.fn().mockReturnValue({}), + setUiOverrides: jest.fn().mockReturnValue(true), + setUiOverridesByUserQueryLanguage: jest.fn(), + setUserQuerySessionId: jest.fn(), + setUserQuerySessionIdByObj: jest.fn(), + getUserQuerySessionId: jest.fn().mockReturnValue(null), + }; +}; + +export const languageServiceMock = { + createSetupContract: createSetupLanguageServiceMock, + createStartContract: createSetupLanguageServiceMock, +}; diff --git a/src/plugins/data/public/query/query_string/language_service/language_service.ts b/src/plugins/data/public/query/query_string/language_service/language_service.ts new file mode 100644 index 000000000000..328912a78666 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/language_service.ts @@ -0,0 +1,145 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { LanguageConfig } from './types'; +import { getDQLLanguageConfig, getLuceneLanguageConfig } from './lib'; +import { ISearchInterceptor } from '../../../search'; +import { + createEditor, + DQLBody, + QueryEditorExtensionConfig, + SingleLineInput, + UiEnhancements, +} from '../../../ui'; +import { DataStorage, setOverrides as setFieldOverrides } from '../../../../common'; + +export class LanguageService { + private languages: Map = new Map(); + private queryEditorExtensionMap: Record; + + constructor( + private readonly defaultSearchInterceptor: ISearchInterceptor, + private readonly storage: DataStorage + ) { + this.registerDefaultLanguages(); + this.queryEditorExtensionMap = {}; + } + + public __enhance = (enhancements: UiEnhancements) => { + if (enhancements.queryEditorExtension) { + this.queryEditorExtensionMap[enhancements.queryEditorExtension.id] = + enhancements.queryEditorExtension; + } + }; + + /** + * Registers default handlers for index patterns and indices. + */ + private registerDefaultLanguages() { + const defaultEditor = createEditor(SingleLineInput, SingleLineInput, DQLBody); + this.registerLanguage(getDQLLanguageConfig(this.defaultSearchInterceptor, defaultEditor)); + this.registerLanguage(getLuceneLanguageConfig(this.defaultSearchInterceptor, defaultEditor)); + } + + public registerLanguage(config: LanguageConfig): void { + this.languages.set(config.id, config); + } + + public getLanguage(language: string): LanguageConfig | undefined { + return this.languages.get(language); + } + + public getLanguages(): LanguageConfig[] { + return Array.from(this.languages.values()); + } + + public getDefaultLanguage(): LanguageConfig { + return this.languages.get('kuery') || this.languages.values().next().value; + } + + public getQueryEditorExtensionMap() { + return this.queryEditorExtensionMap; + } + + resetUserQuery() { + this.setUserQueryLanguage('kuery'); + this.setUserQueryString(''); + } + + getUserQueryLanguageBlocklist() { + return this.storage.get('userQueryLanguageBlocklist') || []; + } + + // TODO: MQL just filtered return languages here + setUserQueryLanguageBlocklist(languages: string[]) { + this.storage.set( + 'userQueryLanguageBlocklist', + languages.map((language) => language.toLowerCase()) + ); + return true; + } + + getUserQueryLanguage() { + return this.storage.get('userQueryLanguage') || 'kuery'; + } + + setUserQueryLanguage(language: string) { + this.storage.set('userQueryLanguage', language); + this.setUiOverridesByUserQueryLanguage(language); + return true; + } + + getUserQueryString() { + return this.storage.get('userQueryString') || ''; + } + + setUserQueryString(query: string) { + this.storage.set('userQueryString', query); + return true; + } + + getUiOverrides() { + return this.storage.get('uiOverrides') || {}; + } + + setUiOverrides(overrides?: { [key: string]: any }) { + if (!overrides) { + this.storage.remove('uiOverrides'); + setFieldOverrides(undefined); + return true; + } + this.storage.set('uiOverrides', overrides); + setFieldOverrides(overrides.fields); + return true; + } + + setUiOverridesByUserQueryLanguage(language: string) { + const queryEnhancement = this.languages.get(language); + if (queryEnhancement) { + const { fields = {} } = queryEnhancement; + this.setUiOverrides({ fields }); + } else { + this.setUiOverrides({ fields: undefined }); + } + } + + setUserQuerySessionId(dataSourceName: string, sessionId: string | null) { + if (sessionId !== null) { + sessionStorage.setItem(`async-query-session-id_${dataSourceName}`, sessionId); + } + } + + setUserQuerySessionIdByObj = (dataSourceName: string, obj: Record) => { + const sessionId = + 'sessionId'.split('.').reduce((acc: any, part: string) => acc && acc[part], obj) || null; + this.setUserQuerySessionId(dataSourceName, sessionId); + }; + + getUserQuerySessionId = (dataSourceName: string) => { + return sessionStorage.getItem(`async-query-session-id_${dataSourceName}`); + }; +} + +export type LanguageServiceContract = PublicMethodsOf; diff --git a/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts b/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts new file mode 100644 index 000000000000..d13125b9d479 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/lib/dql_language.ts @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { LanguageConfig } from '../types'; +import { ISearchInterceptor } from '../../../../search'; + +export const getDQLLanguageConfig = ( + search: ISearchInterceptor, + defaultEditor: any +): LanguageConfig => { + return { + id: 'kuery', + title: 'DQL', + search, + getQueryString(_) { + return ''; + }, + editor: defaultEditor, + fields: { + filterable: true, + visualizable: true, + }, + showDocLinks: true, + editorSupportedAppNames: ['discover'], + }; +}; diff --git a/src/plugins/data/public/ui/settings/index.ts b/src/plugins/data/public/query/query_string/language_service/lib/index.ts similarity index 54% rename from src/plugins/data/public/ui/settings/index.ts rename to src/plugins/data/public/query/query_string/language_service/lib/index.ts index cb6d9d1c8925..42b8f7f2fb18 100644 --- a/src/plugins/data/public/ui/settings/index.ts +++ b/src/plugins/data/public/query/query_string/language_service/lib/index.ts @@ -3,4 +3,5 @@ * SPDX-License-Identifier: Apache-2.0 */ -export { Settings, DataSettings, createSettings } from './settings'; +export * from './dql_language'; +export * from './lucene_language'; diff --git a/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts b/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts new file mode 100644 index 000000000000..f63e0a8b42c6 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/lib/lucene_language.ts @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { LanguageConfig } from '../types'; +import { ISearchInterceptor } from '../../../../search'; + +export const getLuceneLanguageConfig = ( + search: ISearchInterceptor, + defaultEditor: any +): LanguageConfig => { + return { + id: 'lucene', + title: 'Lucene', + search, + getQueryString(_) { + return ''; + }, + editor: defaultEditor, + fields: { + filterable: true, + visualizable: true, + }, + showDocLinks: true, + editorSupportedAppNames: ['discover'], + }; +}; diff --git a/src/plugins/data/public/query/query_string/language_service/types.ts b/src/plugins/data/public/query/query_string/language_service/types.ts new file mode 100644 index 000000000000..5e556e188068 --- /dev/null +++ b/src/plugins/data/public/query/query_string/language_service/types.ts @@ -0,0 +1,30 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ISearchInterceptor } from '../../../search'; +import { Query, QueryEditorExtensionConfig } from '../../../../public'; +import { EditorInstance } from '../../../ui/query_editor/editors'; + +export interface EditorEnhancements { + queryEditorExtension?: QueryEditorExtensionConfig; +} + +export interface LanguageConfig { + id: string; + title: string; + search: ISearchInterceptor; + getQueryString: (query: Query) => string; + editor: ( + collapsedProps: any, + expandedProps: any, + bodyProps: any + ) => EditorInstance; + fields?: { + filterable?: boolean; + visualizable?: boolean; + }; + showDocLinks?: boolean; + editorSupportedAppNames?: string[]; +} diff --git a/src/plugins/data/public/query/query_string/query_history.ts b/src/plugins/data/public/query/query_string/query_history.ts index 17e5f2cd1494..80dfa4b5d560 100644 --- a/src/plugins/data/public/query/query_string/query_history.ts +++ b/src/plugins/data/public/query/query_string/query_history.ts @@ -3,8 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { DataStorage, SimpleDataSet } from 'src/plugins/data/common'; import { BehaviorSubject } from 'rxjs'; +import { DataStorage, Dataset } from '../../../common'; import { Query, TimeRange } from '../..'; // Todo: Implement a more advanced QueryHistory class when needed for recent query history @@ -35,7 +35,7 @@ export class QueryHistory { return () => subscription.unsubscribe(); } - addQueryToHistory(dataSet: SimpleDataSet, query: Query, dateRange?: TimeRange) { + addQueryToHistory(dataset: Dataset, query: Query, dateRange?: TimeRange) { const keys = this.getHistoryKeys(); keys.splice(0, 500); // only maintain most recent X; keys.forEach((key) => { @@ -45,7 +45,7 @@ export class QueryHistory { const timestamp = new Date().getTime(); const k = 'query_' + timestamp; this.storage.set(k, { - dataSet, + dataset, time: timestamp, query, dateRange, diff --git a/src/plugins/data/public/query/query_string/query_string_manager.mock.ts b/src/plugins/data/public/query/query_string/query_string_manager.mock.ts index 82ebf586ab3d..95374d1885f0 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.mock.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.mock.ts @@ -29,8 +29,20 @@ */ import { QueryStringContract } from '.'; +import { Query, Dataset } from '../../../common'; +import { datasetServiceMock } from './dataset_service/dataset_service.mock'; +import { languageServiceMock } from './language_service/language_service.mock'; + +const createSetupContractMock = (isEnhancementsEnabled: boolean = false) => { + const datasetService = datasetServiceMock.createSetupContract(); + const languageService = languageServiceMock.createSetupContract(); + + const defaultQuery: Query = { + query: '', + language: 'kuery', + ...(isEnhancementsEnabled ? { dataset: datasetService.getDefault() } : {}), + }; -const createSetupContractMock = () => { const queryStringManagerMock: jest.Mocked = { getQuery: jest.fn(), setQuery: jest.fn(), @@ -38,7 +50,20 @@ const createSetupContractMock = () => { getDefaultQuery: jest.fn(), formatQuery: jest.fn(), clearQuery: jest.fn(), + addToQueryHistory: jest.fn(), + getQueryHistory: jest.fn().mockReturnValue([]), + clearQueryHistory: jest.fn(), + changeQueryHistory: jest.fn().mockReturnValue(() => {}), + getInitialQuery: jest.fn().mockReturnValue(defaultQuery), + getInitialQueryByLanguage: jest.fn().mockReturnValue(defaultQuery), + getDatasetService: jest.fn().mockReturnValue(datasetService), + getLanguageService: jest.fn().mockReturnValue(languageService), + getInitialQueryByDataset: jest.fn().mockImplementation((newDataset: Dataset) => ({ + ...defaultQuery, + dataset: newDataset, + })), }; + return queryStringManagerMock; }; diff --git a/src/plugins/data/public/query/query_string/query_string_manager.test.ts b/src/plugins/data/public/query/query_string/query_string_manager.test.ts index b9feb3be30d1..1d7a8d9cf00b 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.test.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.test.ts @@ -31,15 +31,22 @@ import { QueryStringManager } from './query_string_manager'; import { coreMock } from '../../../../../core/public/mocks'; import { Query } from '../../../common/query'; -import { DataStorage } from '../../../../data/common'; +import { ISearchInterceptor } from '../../search'; +import { DataStorage } from 'src/plugins/data/common'; describe('QueryStringManager', () => { let service: QueryStringManager; + let storage: DataStorage; + let mockSearchInterceptor: jest.Mocked; beforeEach(() => { + storage = new DataStorage(window.localStorage, 'opensearch_dashboards.'); + mockSearchInterceptor = {} as jest.Mocked; + service = new QueryStringManager( - new DataStorage(window.localStorage, 'opensearch_dashboards.'), - coreMock.createSetup().uiSettings + storage, + coreMock.createSetup().uiSettings, + mockSearchInterceptor ); }); diff --git a/src/plugins/data/public/query/query_string/query_string_manager.ts b/src/plugins/data/public/query/query_string/query_string_manager.ts index 98a348b58254..6bbc5706b64b 100644 --- a/src/plugins/data/public/query/query_string/query_string_manager.ts +++ b/src/plugins/data/public/query/query_string/query_string_manager.ts @@ -31,36 +31,42 @@ import { BehaviorSubject } from 'rxjs'; import { skip } from 'rxjs/operators'; import { CoreStart } from 'opensearch-dashboards/public'; -import { DataStorage, Query, SimpleDataSet, TimeRange, UI_SETTINGS } from '../../../common'; +import { isEqual } from 'lodash'; +import { Dataset, DataStorage, Query, TimeRange, UI_SETTINGS } from '../../../common'; import { createHistory, QueryHistory } from './query_history'; +import { DatasetService, DatasetServiceContract } from './dataset_service'; +import { LanguageService, LanguageServiceContract } from './language_service'; +import { ISearchInterceptor } from '../../search'; export class QueryStringManager { private query$: BehaviorSubject; private queryHistory: QueryHistory; + private datasetService!: DatasetServiceContract; + private languageService!: LanguageServiceContract; constructor( private readonly storage: DataStorage, - private readonly uiSettings: CoreStart['uiSettings'] + private readonly uiSettings: CoreStart['uiSettings'], + private readonly defaultSearchInterceptor: ISearchInterceptor ) { this.query$ = new BehaviorSubject(this.getDefaultQuery()); this.queryHistory = createHistory({ storage }); + this.datasetService = new DatasetService(uiSettings); + this.languageService = new LanguageService(this.defaultSearchInterceptor, this.storage); } private getDefaultQueryString() { return this.storage.get('userQueryString') || ''; } - private getDefaultLanguage() { - return ( - this.storage.get('userQueryLanguage') || - this.uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE) - ); - } - public getDefaultQuery() { return { query: this.getDefaultQueryString(), language: this.getDefaultLanguage(), + ...(this.uiSettings && + this.uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) && { + dataset: this.datasetService?.getDefault(), + }), }; } @@ -71,6 +77,7 @@ export class QueryStringManager { return { query, language: this.getDefaultLanguage(), + dataset: this.datasetService?.getDefault(), }; } else { return query; @@ -89,10 +96,11 @@ export class QueryStringManager { * Updates the query. * @param {Query} query */ - public setQuery = (query: Query) => { + public setQuery = (query: Partial) => { const curQuery = this.query$.getValue(); - if (query?.language !== curQuery.language || query?.query !== curQuery.query) { - this.query$.next(query); + const newQuery = { ...curQuery, ...query }; + if (!isEqual(curQuery, newQuery)) { + this.query$.next(newQuery); } }; @@ -104,7 +112,7 @@ export class QueryStringManager { }; // Todo: update this function to use the Query object when it is udpated, Query object should include time range and dataset - public addToQueryHistory(dataSet: SimpleDataSet, query: Query, timeRange?: TimeRange) { + public addToQueryHistory(dataSet: Dataset, query: Query, timeRange?: TimeRange) { if (query.query) { this.queryHistory.addQueryToHistory(dataSet, query, timeRange); } @@ -121,6 +129,51 @@ export class QueryStringManager { public changeQueryHistory(listener: (reqs: any[]) => void) { return this.queryHistory.change(listener); } + + public getDatasetService = () => { + return this.datasetService; + }; + + public getLanguageService = () => { + return this.languageService; + }; + + public getInitialQuery = () => { + return this.getInitialQueryByLanguage(this.query$.getValue().language); + }; + + public getInitialQueryByLanguage = (languageId: string) => { + const curQuery = this.query$.getValue(); + const language = this.languageService.getLanguage(languageId); + const dataset = curQuery.dataset; + const input = language?.getQueryString(curQuery) || ''; + + return { + query: input, + language: languageId, + dataset, + }; + }; + + public getInitialQueryByDataset = (newDataset: Dataset) => { + const curQuery = this.query$.getValue(); + const languageId = curQuery.language; + const language = this.languageService.getLanguage(languageId); + const newQuery = { ...curQuery, dataset: newDataset }; + const input = language?.getQueryString(newQuery) || ''; + + return { + ...newQuery, + query: input, + }; + }; + + private getDefaultLanguage() { + return ( + this.storage.get('userQueryLanguage') || + this.uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE) + ); + } } export type QueryStringContract = PublicMethodsOf; diff --git a/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts b/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts index 17b9de0f4872..2f804f711c1e 100644 --- a/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts +++ b/src/plugins/data/public/query/state_sync/connect_to_query_state.test.ts @@ -52,6 +52,7 @@ import { TimefilterContract } from '../timefilter'; import { QueryState } from './types'; import { createBrowserHistory, History } from 'history'; import { QueryStringContract } from '../query_string'; +import { ISearchInterceptor } from '../../search'; const connectStorageToQueryStateFn = ( query: QueryStart, @@ -112,12 +113,15 @@ describe('connect_storage_to_query_state', () => { let aF1: Filter; let aF2: Filter; let q1: Query; + let mockSearchInterceptor: jest.Mocked; beforeEach(() => { const queryService = new QueryService(); + mockSearchInterceptor = {} as jest.Mocked; queryService.setup({ uiSettings: setupMock.uiSettings, storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), + defaultSearchInterceptor: mockSearchInterceptor, }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, @@ -215,6 +219,7 @@ describe('connect_to_global_state', () => { let filterManagerChangeSub: Subscription; let filterManagerChangeTriggered = jest.fn(); let indexPatternsMock: IndexPatternsService; + let mockSearchInterceptor: jest.Mocked; let gF1: Filter; let gF2: Filter; @@ -223,9 +228,11 @@ describe('connect_to_global_state', () => { beforeEach(() => { const queryService = new QueryService(); + mockSearchInterceptor = {} as jest.Mocked; queryService.setup({ uiSettings: setupMock.uiSettings, storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), + defaultSearchInterceptor: mockSearchInterceptor, }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, @@ -453,6 +460,7 @@ describe('connect_to_app_state', () => { let filterManagerChangeSub: Subscription; let filterManagerChangeTriggered = jest.fn(); let indexPatternsMock: IndexPatternsService; + let mockSearchInterceptor; let gF1: Filter; let gF2: Filter; @@ -461,9 +469,11 @@ describe('connect_to_app_state', () => { beforeEach(() => { const queryService = new QueryService(); + mockSearchInterceptor = {} as jest.Mocked; queryService.setup({ uiSettings: setupMock.uiSettings, storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), + defaultSearchInterceptor: mockSearchInterceptor, }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, @@ -639,14 +649,17 @@ describe('filters with different state', () => { let filterManagerChangeSub: Subscription; let filterManagerChangeTriggered = jest.fn(); let indexPatternsMock: IndexPatternsService; + let mockSearchInterceptor; let filter: Filter; beforeEach(() => { const queryService = new QueryService(); + mockSearchInterceptor = {} as jest.Mocked; queryService.setup({ uiSettings: setupMock.uiSettings, storage: new DataStorage(window.localStorage, 'opensearch_dashboards.'), + defaultSearchInterceptor: mockSearchInterceptor, }); queryServiceStart = queryService.start({ uiSettings: setupMock.uiSettings, diff --git a/src/plugins/data/public/query/state_sync/connect_to_query_state.ts b/src/plugins/data/public/query/state_sync/connect_to_query_state.ts index 55fe08fa9106..66e212bd6468 100644 --- a/src/plugins/data/public/query/state_sync/connect_to_query_state.ts +++ b/src/plugins/data/public/query/state_sync/connect_to_query_state.ts @@ -38,12 +38,7 @@ import { } from '../../../../opensearch_dashboards_utils/public'; import { QuerySetup, QueryStart } from '../query_service'; import { QueryState, QueryStateChange } from './types'; -import { - FilterStateStore, - COMPARE_ALL_OPTIONS, - compareFilters, - UI_SETTINGS, -} from '../../../common'; +import { FilterStateStore, COMPARE_ALL_OPTIONS, compareFilters } from '../../../common'; import { validateTimeRange } from '../timefilter'; /** @@ -56,14 +51,10 @@ import { validateTimeRange } from '../timefilter'; */ export const connectStorageToQueryState = async ( { - dataSetManager, filterManager, queryString, state$, - }: Pick< - QueryStart | QuerySetup, - 'timefilter' | 'filterManager' | 'queryString' | 'dataSetManager' | 'state$' - >, + }: Pick, OsdUrlStateStorage: IOsdUrlStateStorage, syncConfig: { filters: FilterStateStore; @@ -80,17 +71,10 @@ export const connectStorageToQueryState = async ( if (syncConfig.filters === FilterStateStore.APP_STATE) { syncKeys.push('appFilters'); } - if (syncConfig.dataSet) { - syncKeys.push('dataSet'); - } const initialStateFromURL: QueryState = OsdUrlStateStorage.get('_q') ?? { query: queryString.getDefaultQuery(), filters: filterManager.getAppFilters(), - ...(uiSettings && - uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) && { - dataSet: dataSetManager.getDataSet(), - }), }; // set up initial '_q' flag in the URL to sync query and filter changes @@ -106,20 +90,6 @@ export const connectStorageToQueryState = async ( } } - if ( - syncConfig.dataSet && - !_.isEqual(initialStateFromURL.dataSet, dataSetManager.getDataSet()) - ) { - if (initialStateFromURL.dataSet) { - dataSetManager.setDataSet(_.cloneDeep(initialStateFromURL.dataSet)); - } else { - const defaultDataSet = await dataSetManager.getDefaultDataSet(); - if (defaultDataSet) { - dataSetManager.setDataSet(defaultDataSet); - } - } - } - if (syncConfig.filters === FilterStateStore.APP_STATE) { if ( !initialStateFromURL.filters || @@ -152,10 +122,6 @@ export const connectStorageToQueryState = async ( newState.filters = filterManager.getAppFilters(); } - if (syncConfig.dataSet && changes.dataSet) { - newState.dataSet = dataSetManager.getDataSet(); - } - return newState; }) ) @@ -185,12 +151,8 @@ export const connectToQueryState = ( timefilter: { timefilter }, filterManager, queryString, - dataSetManager, state$, - }: Pick< - QueryStart | QuerySetup, - 'timefilter' | 'filterManager' | 'dataSetManager' | 'queryString' | 'state$' - >, + }: Pick, stateContainer: BaseStateContainer, syncConfig: { time?: boolean; @@ -223,9 +185,6 @@ export const connectToQueryState = ( break; } } - if (syncConfig.dataSet) { - syncKeys.push('dataSet'); - } // initial syncing // TODO: @@ -280,11 +239,6 @@ export const connectToQueryState = ( } } - if (syncConfig.dataSet && !initialState.dataSet) { - initialState.dataSet = dataSetManager.getDefaultDataSet(); - initialDirty = true; - } - if (initialDirty) { stateContainer.set({ ...stateContainer.get(), ...initialState }); } @@ -322,9 +276,6 @@ export const connectToQueryState = ( newState.filters = filterManager.getAppFilters(); } } - if (syncConfig.dataSet && changes.dataSet) { - newState.dataSet = dataSetManager.getDataSet(); - } return newState; }) ) @@ -384,21 +335,6 @@ export const connectToQueryState = ( } } - if (syncConfig.dataSet) { - const currentDataSet = dataSetManager.getDataSet(); - if (!_.isEqual(state.dataSet, currentDataSet)) { - if (state.dataSet) { - dataSetManager.setDataSet(state.dataSet); - } else { - const defaultDataSet = dataSetManager.getDefaultDataSet(); - if (defaultDataSet) { - dataSetManager.setDataSet(defaultDataSet); - stateContainer.set({ ...stateContainer.get(), dataSet: defaultDataSet }); - } - } - } - } - updateInProgress = false; }), ]; diff --git a/src/plugins/data/public/query/state_sync/create_global_query_observable.ts b/src/plugins/data/public/query/state_sync/create_global_query_observable.ts index a77b3f159e25..8abcb3ece18d 100644 --- a/src/plugins/data/public/query/state_sync/create_global_query_observable.ts +++ b/src/plugins/data/public/query/state_sync/create_global_query_observable.ts @@ -36,18 +36,15 @@ import { QueryState, QueryStateChange } from './index'; import { createStateContainer } from '../../../../opensearch_dashboards_utils/public'; import { isFilterPinned, compareFilters, COMPARE_ALL_OPTIONS } from '../../../common'; import { QueryStringContract } from '../query_string'; -import { DataSetContract } from '../dataset_manager'; export function createQueryStateObservable({ timefilter: { timefilter }, filterManager, queryString, - dataSetManager, }: { timefilter: TimefilterSetup; filterManager: FilterManager; queryString: QueryStringContract; - dataSetManager: DataSetContract; }): Observable<{ changes: QueryStateChange; state: QueryState }> { return new Observable((subscriber) => { const state = createStateContainer({ @@ -55,7 +52,6 @@ export function createQueryStateObservable({ refreshInterval: timefilter.getRefreshInterval(), filters: filterManager.getFilters(), query: queryString.getQuery(), - dataSet: dataSetManager.getDataSet(), }); let currentChange: QueryStateChange = {}; @@ -64,10 +60,6 @@ export function createQueryStateObservable({ currentChange.query = true; state.set({ ...state.get(), query: queryString.getQuery() }); }), - dataSetManager.getUpdates$().subscribe(() => { - currentChange.dataSet = true; - state.set({ ...state.get(), dataSet: dataSetManager.getDataSet() }); - }), timefilter.getTimeUpdate$().subscribe(() => { currentChange.time = true; state.set({ ...state.get(), time: timefilter.getTime() }); diff --git a/src/plugins/data/public/query/state_sync/sync_state_with_url.ts b/src/plugins/data/public/query/state_sync/sync_state_with_url.ts index f34c0912200c..e8041a8c016b 100644 --- a/src/plugins/data/public/query/state_sync/sync_state_with_url.ts +++ b/src/plugins/data/public/query/state_sync/sync_state_with_url.ts @@ -38,7 +38,6 @@ import { QuerySetup, QueryStart } from '../query_service'; import { connectToQueryState } from './connect_to_query_state'; import { QueryState } from './types'; import { FilterStateStore } from '../../../common/opensearch_query/filters'; -import { UI_SETTINGS } from '../../../common'; const GLOBAL_STATE_STORAGE_KEY = '_g'; @@ -48,26 +47,18 @@ const GLOBAL_STATE_STORAGE_KEY = '_g'; * @param osdUrlStateStorage to use for syncing */ export const syncQueryStateWithUrl = ( - query: Pick< - QueryStart | QuerySetup, - 'filterManager' | 'timefilter' | 'queryString' | 'dataSetManager' | 'state$' - >, + query: Pick, osdUrlStateStorage: IOsdUrlStateStorage, uiSettings?: CoreStart['uiSettings'] ) => { const { timefilter: { timefilter }, filterManager, - dataSetManager, } = query; const defaultState: QueryState = { time: timefilter.getTime(), refreshInterval: timefilter.getRefreshInterval(), filters: filterManager.getGlobalFilters(), - ...(uiSettings && - uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED) && { - dataSet: dataSetManager.getDataSet(), - }), }; // retrieve current state from `_g` url @@ -89,7 +80,6 @@ export const syncQueryStateWithUrl = ( refreshInterval: true, time: true, filters: FilterStateStore.GLOBAL_STATE, - dataSet: true, }); // if there weren't any initial state in url, diff --git a/src/plugins/data/public/query/state_sync/types.ts b/src/plugins/data/public/query/state_sync/types.ts index 8134a7208f13..4c7350e70172 100644 --- a/src/plugins/data/public/query/state_sync/types.ts +++ b/src/plugins/data/public/query/state_sync/types.ts @@ -28,7 +28,7 @@ * under the License. */ -import { Filter, RefreshInterval, TimeRange, Query, SimpleDataSet } from '../../../common'; +import { Filter, RefreshInterval, TimeRange, Query, Dataset } from '../../../common'; /** * All query state service state @@ -38,7 +38,8 @@ export interface QueryState { refreshInterval?: RefreshInterval; filters?: Filter[]; query?: Query; - dataSet?: SimpleDataSet; + // TODO: remove once query object correctly has dataset + dataset?: Dataset; } type QueryStateChangePartial = { diff --git a/src/plugins/data/public/query/types.ts b/src/plugins/data/public/query/types.ts new file mode 100644 index 000000000000..ee359f0939a2 --- /dev/null +++ b/src/plugins/data/public/query/types.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { IUiSettingsClient, SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { Observable } from 'rxjs'; +import { DataStorage } from '../../common'; +import { IndexPattern, IndexPatternsService } from '../index_patterns'; +import { ISearchInterceptor } from '../search'; +import { FilterManager } from './filter_manager'; +import { QueryStringContract } from './query_string'; +import { QueryStateChange, QueryState } from './state_sync'; +import { createAddToQueryLog } from './lib'; +import { createSavedQueryService } from './saved_query'; +import { TimefilterSetup } from './timefilter'; + +export interface IQuerySetup { + filterManager: FilterManager; + timefilter: TimefilterSetup; + queryString: QueryStringContract; + state$: Observable<{ changes: QueryStateChange; state: QueryState }>; +} + +export interface IQueryStart { + addToQueryLog: ReturnType; + filterManager: FilterManager; + queryString: QueryStringContract; + savedQueries: ReturnType; + state$: Observable<{ changes: QueryStateChange; state: QueryState }>; + timefilter: TimefilterSetup; + getOpenSearchQuery: (indexPattern: IndexPattern) => any; +} + +/** @internal */ +export interface QueryServiceSetupDependencies { + storage: DataStorage; + uiSettings: IUiSettingsClient; + defaultSearchInterceptor: ISearchInterceptor; +} + +/** @internal */ +export interface QueryServiceStartDependencies { + savedObjectsClient: SavedObjectsClientContract; + storage: DataStorage; + uiSettings: IUiSettingsClient; + indexPatterns: IndexPatternsService; +} diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index bfd0bc1ed780..f5ff39c40c4f 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -56,5 +56,5 @@ export { export { getOpenSearchPreference } from './opensearch_search'; -export { SearchInterceptor, SearchInterceptorDeps } from './search_interceptor'; +export { SearchInterceptor, SearchInterceptorDeps, ISearchInterceptor } from './search_interceptor'; export * from './errors'; diff --git a/src/plugins/data/public/search/mocks.ts b/src/plugins/data/public/search/mocks.ts index 736de838df8d..826d0ed69fab 100644 --- a/src/plugins/data/public/search/mocks.ts +++ b/src/plugins/data/public/search/mocks.ts @@ -36,6 +36,7 @@ function createSetupContract(): jest.Mocked { return { aggs: searchAggsSetupMock(), __enhance: jest.fn(), + getDefaultSearchInterceptor: jest.fn(), }; } diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 5516b4abc79d..edf98b8570f2 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -62,9 +62,8 @@ import { IDataFrame, IDataFrameResponse, createDataFrameCache, - dataFrameToSpec, } from '../../common/data_frames'; -import { getQueryService, getUiService } from '../services'; +import { getQueryService } from '../services'; import { UI_SETTINGS } from '../../common'; /** @internal */ @@ -127,6 +126,7 @@ export class SearchService implements Plugin { __enhance: (enhancements: SearchEnhancements) => { this.searchInterceptor = enhancements.searchInterceptor; }, + getDefaultSearchInterceptor: () => this.defaultSearchInterceptor, }; } @@ -135,20 +135,18 @@ export class SearchService implements Plugin { { fieldFormats, indexPatterns }: SearchServiceStartDependencies ): ISearchStart { const search = ((request, options) => { - const selectedLanguage = getQueryService().queryString.getQuery().language; - const uiService = getUiService(); - const enhancement = uiService.Settings.getQueryEnhancements(selectedLanguage); - uiService.Settings.setUiOverridesByUserQueryLanguage(selectedLanguage); const isEnhancedEnabled = uiSettings.get(UI_SETTINGS.QUERY_ENHANCEMENTS_ENABLED); - - if (enhancement) { - if (!isEnhancedEnabled) { - notifications.toasts.addWarning( - `Query enhancements are disabled. Please enable to use: ${selectedLanguage}.` - ); + if (isEnhancedEnabled) { + const queryStringManager = getQueryService().queryString; + const language = queryStringManager.getQuery().language; + const languageConfig = queryStringManager.getLanguageService().getLanguage(language); + queryStringManager.getLanguageService().setUiOverridesByUserQueryLanguage(language); + + if (languageConfig) { + return languageConfig.search.search(request, options); } - return enhancement.search.search(request, options); } + return this.defaultSearchInterceptor.search(request, options); }) as ISearchGeneric; @@ -158,28 +156,7 @@ export class SearchService implements Plugin { const dfService: DataFrameService = { get: () => this.dfCache.get(), set: async (dataFrame: IDataFrame) => { - if (this.dfCache.get() && this.dfCache.get()?.name !== dataFrame.name) { - indexPatterns.clearCache(this.dfCache.get()!.name, false); - } - - if ( - dataFrame.meta && - dataFrame.meta.queryConfig && - 'dataSource' in dataFrame.meta.queryConfig - ) { - const dataSource = await indexPatterns.findDataSourceByTitle( - dataFrame.meta.queryConfig.dataSource - ); - dataFrame.meta.queryConfig.dataSourceId = dataSource?.id; - } this.dfCache.set(dataFrame); - const dataSetName = `${dataFrame.meta?.queryConfig?.dataSourceId ?? ''}.${dataFrame.name}`; - const existingIndexPattern = await indexPatterns.get(dataSetName, true); - const dataSet = await indexPatterns.create( - dataFrameToSpec(dataFrame, existingIndexPattern?.id ?? dataSetName), - !existingIndexPattern?.id - ); - indexPatterns.saveToCache(dataSetName, dataSet); }, clear: () => { if (this.dfCache.get() === undefined) return; diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index 29dc37b41c91..d34271ef7568 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -54,6 +54,7 @@ export interface ISearchSetup { * @internal */ __enhance: (enhancements: SearchEnhancements) => void; + getDefaultSearchInterceptor: () => ISearchInterceptor; } /** diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 236ebfbb6e00..01552c822ede 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -35,16 +35,16 @@ import { AutocompleteSetup, AutocompleteStart } from './autocomplete'; import { FieldFormatsSetup, FieldFormatsStart } from './field_formats'; import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } from './actions'; import { ISearchSetup, ISearchStart, SearchEnhancements } from './search'; -import { QuerySetup, QueryStart } from './query'; +import { EditorEnhancements, QuerySetup, QueryStart } from './query'; import { IndexPatternsContract } from './index_patterns'; import { UsageCollectionSetup } from '../../usage_collection/public'; import { DataSourceStart } from './data_sources/datasource_services/types'; -import { IUiStart, UiEnhancements } from './ui'; +import { IUiStart } from './ui'; import { DataStorage } from '../common'; export interface DataPublicPluginEnhancements { search?: SearchEnhancements; - ui?: UiEnhancements; + editor?: EditorEnhancements; } export interface DataSetupDependencies { diff --git a/src/plugins/data/public/ui/_index.scss b/src/plugins/data/public/ui/_index.scss index 4aa425041f58..9ab4ca672b38 100644 --- a/src/plugins/data/public/ui/_index.scss +++ b/src/plugins/data/public/ui/_index.scss @@ -2,6 +2,6 @@ @import "./typeahead/index"; @import "./saved_query_management/index"; @import "./query_string_input/index"; -@import "./dataset_navigator/index"; +@import "./dataset_selector/index"; @import "./query_editor/index"; @import "./shard_failure_modal/shard_failure_modal"; diff --git a/src/plugins/data/public/ui/dataset_navigator/_dataset_navigator.scss b/src/plugins/data/public/ui/dataset_navigator/_dataset_navigator.scss deleted file mode 100644 index 875a2d62635f..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/_dataset_navigator.scss +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -.dataSetNavigator { - padding: $euiSizeXS; - color: $euiColorPrimaryText; - - &__icon { - margin-right: 4px; - } - - &__loading { - padding: $euiSizeS; - } - - &__menu { - width: 365px; - - .euiContextMenu__panel > div { - @include euiYScrollWithShadows; - - max-height: 60vh; - } - } -} - -.dataSetNavigatorFormWrapper { - padding: $euiSizeS; -} diff --git a/src/plugins/data/public/ui/dataset_navigator/_index.scss b/src/plugins/data/public/ui/dataset_navigator/_index.scss deleted file mode 100644 index 53acdffad43d..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import "./dataset_navigator"; diff --git a/src/plugins/data/public/ui/dataset_navigator/create_dataset_navigator.tsx b/src/plugins/data/public/ui/dataset_navigator/create_dataset_navigator.tsx deleted file mode 100644 index b6a6274e13cf..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/create_dataset_navigator.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from 'react'; -import { HttpStart, SavedObjectsClientContract } from 'opensearch-dashboards/public'; -import { DataSetNavigator, DataSetNavigatorProps } from './'; -import { DataSetContract } from '../../query'; - -// Updated function signature to include additional dependencies -export function createDataSetNavigator( - savedObjectsClient: SavedObjectsClientContract, - http: HttpStart, - dataSetManager: DataSetContract -) { - // Return a function that takes props, omitting the dependencies from the props type - return (props: Omit) => ( - - ); -} diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/catalog_cache/cache_intercept.ts b/src/plugins/data/public/ui/dataset_navigator/lib/catalog_cache/cache_intercept.ts deleted file mode 100644 index 0526cfd51212..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/lib/catalog_cache/cache_intercept.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { HttpFetchOptionsWithPath, IHttpInterceptController } from 'opensearch-dashboards/public'; -import { SECURITY_DASHBOARDS_LOGOUT_URL } from '../constants'; -import { CatalogCacheManager } from './cache_manager'; - -export function catalogRequestIntercept(): any { - return ( - fetchOptions: Readonly, - _controller: IHttpInterceptController - ) => { - if (fetchOptions.path.includes(SECURITY_DASHBOARDS_LOGOUT_URL)) { - // Clears all user catalog cache details - CatalogCacheManager.clearDataSourceCache(); - CatalogCacheManager.clearAccelerationsCache(); - CatalogCacheManager.clearExternalDataSourcesCache(); - CatalogCacheManager.clearRecentDataSetsCache(); - } - }; -} diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/catalog_cache/index.tsx b/src/plugins/data/public/ui/dataset_navigator/lib/catalog_cache/index.tsx deleted file mode 100644 index 5449277b2bd8..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/lib/catalog_cache/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './cache_intercept'; -export * from './cache_loader'; -export * from './cache_manager'; diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/index.tsx b/src/plugins/data/public/ui/dataset_navigator/lib/index.tsx deleted file mode 100644 index 98c2ef4e9f92..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/lib/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export * from './catalog_cache'; -export * from './requests'; -export * from './utils'; diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_catalog_cache_status.ts b/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_catalog_cache_status.ts deleted file mode 100644 index 697852fdd772..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_catalog_cache_status.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export enum DirectQueryLoadingStatus { - SUCCESS = 'success', - FAILED = 'failed', - RUNNING = 'running', - SCHEDULED = 'scheduled', - CANCELED = 'canceled', - WAITING = 'waiting', - INITIAL = 'initial', -} - -const catalogCacheFetchingStatus = [ - DirectQueryLoadingStatus.RUNNING, - DirectQueryLoadingStatus.WAITING, - DirectQueryLoadingStatus.SCHEDULED, -]; - -export const isCatalogCacheFetching = (...statuses: DirectQueryLoadingStatus[]) => { - return statuses.some((status: DirectQueryLoadingStatus) => - catalogCacheFetchingStatus.includes(status) - ); -}; diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_data_sources.ts b/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_data_sources.ts deleted file mode 100644 index 3c62a2116b4d..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_data_sources.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; -import { SimpleDataSource } from '../../../../../common'; - -export const fetchDataSources = async (client: SavedObjectsClientContract) => { - const resp = await client.find({ - type: 'data-source', - perPage: 10000, - }); - const dataSources: SimpleDataSource[] = [{ id: '', name: 'Local Cluster', type: 'data-source' }]; - return dataSources.concat([ - ...(resp.savedObjects.map((savedObject) => ({ - id: savedObject.id, - name: savedObject.attributes.title, - type: 'data-source', - })) as SimpleDataSource[]), - ]); -}; diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_index_patterns.ts b/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_index_patterns.ts deleted file mode 100644 index 3f2cd230300e..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_index_patterns.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; -import { IIndexPattern } from '../.././../..'; -import { SIMPLE_DATA_SOURCE_TYPES, SIMPLE_DATA_SET_TYPES } from '../../../../../common'; - -export const fetchIndexPatterns = async (client: SavedObjectsClientContract, search: string) => { - const resp = await client.find({ - type: 'index-pattern', - fields: ['title', 'timeFieldName', 'references', 'fields'], - search: `${search}*`, - searchFields: ['title'], - perPage: 100, - }); - return resp.savedObjects.map((savedObject) => ({ - id: savedObject.id, - title: savedObject.attributes.title, - timeFieldName: savedObject.attributes.timeFieldName, - fields: savedObject.attributes.fields, - type: SIMPLE_DATA_SET_TYPES.INDEX_PATTERN, - ...(savedObject.references[0] - ? { - dataSourceRef: { - id: savedObject.references[0]?.id, - name: savedObject.references[0]?.name, - type: SIMPLE_DATA_SOURCE_TYPES.DEFAULT, - }, - } - : {}), - })); -}; diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_indices.ts b/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_indices.ts deleted file mode 100644 index ef10c72bc08c..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/lib/utils/fetch_indices.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { map } from 'rxjs/operators'; -import { ISearchStart } from '../../../../search'; - -export const fetchIndices = async (search: ISearchStart, dataSourceId?: string) => { - const buildSearchRequest = () => { - const request = { - params: { - ignoreUnavailable: true, - expand_wildcards: 'all', - index: '*', - body: { - size: 0, // no hits - aggs: { - indices: { - terms: { - field: '_index', - size: 100, - }, - }, - }, - }, - }, - dataSourceId, - }; - - return request; - }; - - const searchResponseToArray = (response: any) => { - const { rawResponse } = response; - return rawResponse.aggregations - ? rawResponse.aggregations.indices.buckets.map((bucket: { key: any }) => bucket.key) - : []; - }; - - return search - .getDefaultSearchInterceptor() - .search(buildSearchRequest()) - .pipe(map(searchResponseToArray)) - .toPromise(); -}; diff --git a/src/plugins/data/public/ui/dataset_navigator/lib/utils/use_polling.ts b/src/plugins/data/public/ui/dataset_navigator/lib/utils/use_polling.ts deleted file mode 100644 index 74fedd6cf110..000000000000 --- a/src/plugins/data/public/ui/dataset_navigator/lib/utils/use_polling.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { useEffect, useRef, useState } from 'react'; - -type FetchFunction = (params?: P) => Promise; - -export interface PollingConfigurations { - tabId: string; -} - -export class UsePolling { - public data: T | null = null; - public error: Error | null = null; - public loading: boolean = true; - private shouldPoll: boolean = false; - private intervalRef?: NodeJS.Timeout; - - constructor( - private fetchFunction: FetchFunction, - private interval: number = 5000, - private onPollingSuccess?: (data: T, configurations: PollingConfigurations) => boolean, - private onPollingError?: (error: Error) => boolean, - private configurations?: PollingConfigurations - ) {} - - async fetchData(params?: P) { - this.loading = true; - try { - const result = await this.fetchFunction(params); - this.data = result; - this.loading = false; - - if (this.onPollingSuccess && this.onPollingSuccess(result, this.configurations!)) { - this.stopPolling(); - } - } catch (err) { - this.error = err as Error; - this.loading = false; - - if (this.onPollingError && this.onPollingError(this.error)) { - this.stopPolling(); - } - } - } - - startPolling(params?: P) { - this.shouldPoll = true; - if (!this.intervalRef) { - this.intervalRef = setInterval(() => { - if (this.shouldPoll) { - this.fetchData(params); - } - }, this.interval); - } - } - - stopPolling() { - this.shouldPoll = false; - if (this.intervalRef) { - clearInterval(this.intervalRef); - this.intervalRef = undefined; - } - } -} - -interface UsePollingReturn { - data: T | null; - loading: boolean; - error: Error | null; - startPolling: (params?: any) => void; - stopPolling: () => void; -} - -export function usePolling( - fetchFunction: FetchFunction, - interval: number = 5000, - onPollingSuccess?: (data: T, configurations: PollingConfigurations) => boolean, - onPollingError?: (error: Error) => boolean, - configurations?: PollingConfigurations -): UsePollingReturn { - const [data, setData] = useState(null); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(true); - const intervalRef = useRef(undefined); - const unmounted = useRef(false); - - const shouldPoll = useRef(false); - - const startPolling = (params?: P) => { - shouldPoll.current = true; - const intervalId = setInterval(() => { - if (shouldPoll.current) { - fetchData(params); - } - }, interval); - intervalRef.current = intervalId; - if (unmounted.current) { - clearInterval(intervalId); - } - }; - - const stopPolling = () => { - shouldPoll.current = false; - clearInterval(intervalRef.current); - }; - - const fetchData = async (params?: P) => { - try { - const result = await fetchFunction(params); - setData(result); - // Check the success condition and stop polling if it's met - if (onPollingSuccess && onPollingSuccess(result, configurations)) { - stopPolling(); - } - } catch (err: unknown) { - setError(err as Error); - - // Check the error condition and stop polling if it's met - if (onPollingError && onPollingError(err as Error)) { - stopPolling(); - } - } finally { - setLoading(false); - } - }; - - useEffect(() => { - return () => { - unmounted.current = true; - }; - }, []); - - return { data, loading, error, startPolling, stopPolling }; -} diff --git a/src/plugins/data/public/ui/dataset_selector/_dataset_explorer.scss b/src/plugins/data/public/ui/dataset_selector/_dataset_explorer.scss new file mode 100644 index 000000000000..0011db04fa29 --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/_dataset_explorer.scss @@ -0,0 +1,28 @@ +.datasetExplorer { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 240px)) minmax(300px, 1fr); + height: 600px; + overflow-x: auto; + border: $euiBorderThin; + + &__column { + display: grid; + grid-template-rows: auto 1fr; + border-right: $euiBorderThin; + + &--empty, + &--leaf { + border-right: none; + } + } + + &__list { + flex-grow: 1; + overflow-y: auto; + } + + &__columnTitle { + padding: $euiSizeS; + border-bottom: $euiBorderThin; + } +} diff --git a/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss b/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss new file mode 100644 index 000000000000..9ec6ca531cf8 --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/_dataset_selector.scss @@ -0,0 +1,14 @@ +.datasetSelector { + &__icon { + margin-right: 4px; + } + + &__advancedButton { + width: 100%; + } + + &__selectable { + width: 365px; + padding: $euiSizeXS; + } +} diff --git a/src/plugins/data/public/ui/dataset_selector/_index.scss b/src/plugins/data/public/ui/dataset_selector/_index.scss new file mode 100644 index 000000000000..b1d4dbe34c68 --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/_index.scss @@ -0,0 +1,2 @@ +@import "./dataset_explorer"; +@import "./dataset_selector"; diff --git a/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx b/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx new file mode 100644 index 000000000000..a319c9a376bd --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/advanced_selector.tsx @@ -0,0 +1,70 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { + BaseDataset, + DATA_STRUCTURE_META_TYPES, + Dataset, + DataStructure, + DEFAULT_DATA, +} from '../../../common'; +import { DatasetExplorer } from './dataset_explorer'; +import { Configurator } from './configurator'; +import { getQueryService } from '../../services'; + +export const AdvancedSelector = ({ + savedObjects, + onSelect, + onCancel, +}: { + savedObjects: SavedObjectsClientContract; + onSelect: (dataset: Dataset) => void; + onCancel: () => void; +}) => { + const queryString = getQueryService().queryString; + + const [path, setPath] = useState([ + { + ...DEFAULT_DATA.STRUCTURES.ROOT, + columnHeader: 'Select data', + hasNext: true, + children: queryString + .getDatasetService() + .getTypes() + .map((type) => { + return { + id: type!.id, + title: type!.title, + type: type!.id, + meta: { + ...type!.meta, + type: DATA_STRUCTURE_META_TYPES.TYPE, + }, + } as DataStructure; + }), + }, + ]); + const [selectedDataset, setSelectedDataset] = useState(); + + return selectedDataset ? ( + setSelectedDataset(undefined)} + /> + ) : ( + setSelectedDataset(dataset)} + onCancel={onCancel} + /> + ); +}; diff --git a/src/plugins/data/public/ui/dataset_selector/configurator.tsx b/src/plugins/data/public/ui/dataset_selector/configurator.tsx new file mode 100644 index 000000000000..32e48691aa87 --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/configurator.tsx @@ -0,0 +1,161 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect, useState } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiFieldText, + EuiForm, + EuiFormRow, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiSelect, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { FormattedMessage } from '@osd/i18n/react'; +import { BaseDataset, Dataset, DatasetField } from '../../../common'; +import { getQueryService, getIndexPatterns } from '../../services'; + +export const Configurator = ({ + baseDataset, + onConfirm, + onCancel, + onPrevious, +}: { + baseDataset: BaseDataset; + onConfirm: (dataset: Dataset) => void; + onCancel: () => void; + onPrevious: () => void; +}) => { + const queryService = getQueryService(); + const queryString = queryService.queryString; + const indexPatternsService = getIndexPatterns(); + const type = queryString.getDatasetService().getType(baseDataset.type); + const languages = type?.supportedLanguages(baseDataset) || []; + + const [dataset, setDataset] = useState(baseDataset); + const [timeFields, setTimeFields] = useState(); + const [timeField, setTimeField] = useState(dataset.timeFieldName); + const [language, setLanguage] = useState(languages[0]); + + useEffect(() => { + const fetchFields = async () => { + const datasetFields = await queryString + .getDatasetService() + .getType(baseDataset.type) + ?.fetchFields(baseDataset); + + const dateFields = datasetFields?.filter((field) => field.type === 'date'); + setTimeFields(dateFields || []); + }; + + fetchFields(); + }, [baseDataset, indexPatternsService, queryString]); + + return ( + <> + + +

+ +

+ +

+ +

+
+
+
+ + + + + + {timeFields && timeFields.length > 0 && ( + + ({ + text: field.displayName || field.name, + value: field.name, + })), + { text: '-----', value: '', disabled: true }, + { text: 'No time field', value: undefined }, + ]} + value={timeField} + onChange={(e) => { + const value = e.target.value === 'undefined' ? undefined : e.target.value; + setTimeField(value); + setDataset({ ...dataset, timeFieldName: value }); + }} + /> + + )} + + ({ + text: languageId, + value: languageId, + }))} + value={language} + onChange={(e) => setLanguage(e.target.value)} + /> + + + + + + + + + + + onConfirm(dataset)} fill> + + + + + ); +}; diff --git a/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx b/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx new file mode 100644 index 000000000000..dd35ce8065b2 --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx @@ -0,0 +1,228 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiIcon, + EuiLink, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, + EuiSelectable, + EuiText, + EuiTitle, + EuiToolTip, +} from '@elastic/eui'; +import { FormattedMessage } from '@osd/i18n/react'; +import { SavedObjectsClientContract } from 'opensearch-dashboards/public'; +import { BaseDataset, DATA_STRUCTURE_META_TYPES, DataStructure } from '../../../common'; +import { QueryStringContract } from '../../query'; + +export const DatasetExplorer = ({ + savedObjects, + queryString, + path, + setPath, + onNext, + onCancel, +}: { + savedObjects: SavedObjectsClientContract; + queryString: QueryStringContract; + path: DataStructure[]; + setPath: (path: DataStructure[]) => void; + onNext: (dataset: BaseDataset) => void; + onCancel: () => void; +}) => { + const [explorerDataset, setExplorerDataset] = useState(undefined); + const [loading, setLoading] = useState(false); + + const selectDataStructure = async (item: DataStructure, newPath: DataStructure[]) => { + const lastPathItem = newPath[newPath.length - 1]; + const nextPath = [...newPath, item]; + + const typeConfig = queryString.getDatasetService().getType(nextPath[1].id); + if (!typeConfig) return; + + if (!lastPathItem.hasNext) { + const dataset = typeConfig!.toDataset(nextPath); + setExplorerDataset(dataset as BaseDataset); + return; + } + + setLoading(true); + const nextDataStructure = await typeConfig.fetch(savedObjects, nextPath); + setLoading(false); + + setPath([...newPath, nextDataStructure]); + }; + + const columnCount = path[path.length - 1]?.hasNext ? path.length + 1 : path.length; + + return ( + <> + + +

+ +

+ +

+ + + Manage data sources + +

+
+
+
+ +
+ {path.map((current, index) => { + const isLast = index === path.length - 1; + const isFinal = isLast && !current.hasNext; + return ( +
+ +

{current.columnHeader}

+
+ ({ + label: child.parent ? `${child.parent.title}::${child.title}` : child.title, + value: child.id, + prepend: child.meta?.type === DATA_STRUCTURE_META_TYPES.TYPE && + child.meta?.icon && , + append: appendIcon(child), + checked: isChecked(child, index, path, explorerDataset), + }))} + onChange={(options) => { + const selected = options.find((option) => option.checked); + if (selected) { + const item = current.children?.find((child) => child.id === selected.value); + if (item) { + selectDataStructure(item, path.slice(0, index + 1)); + } + } + }} + singleSelection + {...(isFinal && { + searchProps: { + compressed: true, + }, + searchable: true, + })} + className="datasetExplorer__selectable" + > + {(list, search) => ( + <> + {isFinal && search} + {list} + + )} + +
+ ); + })} + {!!path[path.length - 1]?.hasNext && } +
+
+ + + + + onNext(explorerDataset!)} + iconType="arrowRight" + iconSide="right" + fill + > + + + + + ); +}; + +const EmptyColumn = () => ( +
+); + +const LoadingEmptyColumn = ({ isLoading }: { isLoading: boolean }) => + isLoading ? ( +
+ +

...

+
+ + {(list) => <>{list}} + +
+ ) : ( + + ); +const appendIcon = (item: DataStructure) => { + if (item.meta?.type === DATA_STRUCTURE_META_TYPES.FEATURE) { + if (item.meta?.icon && item.meta?.tooltip) { + return ( + + + + ); + } else if (item.meta?.icon) { + return ; + } + } + + if (item.meta?.type === DATA_STRUCTURE_META_TYPES.TYPE) { + return ( + + + + ); + } + + return null; +}; + +const isChecked = ( + child: DataStructure, + index: number, + path: DataStructure[], + explorerDataset?: BaseDataset +) => { + if (index === path.length - 1) { + // For the last level, check against the selectedDataSet + return child.id === explorerDataset?.id ? 'on' : undefined; + } + // For other levels, check against the next item in the path + return child.id === path[index + 1]?.id ? 'on' : undefined; +}; diff --git a/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx b/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx new file mode 100644 index 000000000000..ed0bd76fdaf1 --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/dataset_selector.tsx @@ -0,0 +1,196 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useEffect, useMemo, useState, useCallback } from 'react'; +import { + EuiButtonEmpty, + EuiIcon, + EuiPopover, + EuiPopoverTitle, + EuiSelectable, + EuiSelectableOption, + EuiToolTip, +} from '@elastic/eui'; +import { FormattedMessage } from '@osd/i18n/react'; +import { toMountPoint } from '../../../../opensearch_dashboards_react/public'; +import { Dataset, DEFAULT_DATA } from '../../../common'; +import { IDataPluginServices } from '../../types'; +import { AdvancedSelector } from './advanced_selector'; +import { getQueryService } from '../../services'; + +interface DatasetSelectorProps { + selectedDataset?: Dataset; + setSelectedDataset: (dataset: Dataset) => void; + services: IDataPluginServices; +} + +export const DatasetSelector = ({ + selectedDataset, + setSelectedDataset, + services, +}: DatasetSelectorProps) => { + const [isOpen, setIsOpen] = useState(false); + const [datasets, setDatasets] = useState([]); + const { overlays, savedObjects } = services; + + const datasetService = getQueryService().queryString.getDatasetService(); + + const datasetIcon = + datasetService.getType(selectedDataset?.type || '')?.meta.icon.type || 'database'; + + const fetchDatasets = useCallback(async () => { + const typeConfig = datasetService.getType(DEFAULT_DATA.SET_TYPES.INDEX_PATTERN); + if (!typeConfig) return; + + const fetchedIndexPatternDataStructures = await typeConfig.fetch(savedObjects.client, []); + + const fetchedDatasets = + fetchedIndexPatternDataStructures.children?.map((pattern) => + typeConfig.toDataset([pattern]) + ) ?? []; + setDatasets(fetchedDatasets); + + // If no dataset is selected, select the first one + if (!selectedDataset && fetchedDatasets.length > 0) { + setSelectedDataset(fetchedDatasets[0]); + } + }, [datasetService, savedObjects.client, selectedDataset, setSelectedDataset]); + + useEffect(() => { + fetchDatasets(); + }, [fetchDatasets]); + + const togglePopover = useCallback(async () => { + if (!isOpen) { + await fetchDatasets(); + } + setIsOpen(!isOpen); + }, [isOpen, fetchDatasets]); + + const closePopover = useCallback(() => setIsOpen(false), []); + + const options = useMemo(() => { + const newOptions: EuiSelectableOption[] = [ + { + label: 'Index patterns', + isGroupLabel: true, + }, + ]; + + datasets.forEach(({ id, title, type, dataSource }) => { + const label = dataSource ? `${dataSource.title}::${title}` : title; + newOptions.push({ + label, + checked: id === selectedDataset?.id ? 'on' : undefined, + key: id, + prepend: , + }); + }); + + return newOptions; + }, [datasets, selectedDataset?.id, datasetService]); + + const handleOptionChange = useCallback( + (newOptions: EuiSelectableOption[]) => { + const selectedOption = newOptions.find((option) => option.checked === 'on'); + if (selectedOption) { + const foundDataset = datasets.find((dataset) => dataset.id === selectedOption.key); + if (foundDataset) { + closePopover(); + setSelectedDataset(foundDataset); + } + } + }, + [datasets, setSelectedDataset, closePopover] + ); + + const datasetTitle = useMemo(() => { + if (!selectedDataset) { + return 'Select data'; + } + + if (selectedDataset.dataSource) { + return `${selectedDataset.dataSource.title}::${selectedDataset.title}`; + } + + return selectedDataset.title; + }, [selectedDataset]); + + return ( + + + + {datasetTitle} + + + } + isOpen={isOpen} + closePopover={closePopover} + anchorPosition="downLeft" + display="block" + panelPaddingSize="none" + > + + { + closePopover(); + const overlay = overlays?.openModal( + toMountPoint( + { + overlay?.close(); + if (dataset) { + setSelectedDataset(dataset); + } + }} + onCancel={() => overlay?.close()} + /> + ) + ); + }} + > + + + + + {(list, search) => ( + <> + {search} + {list} + + )} + + + ); +}; diff --git a/src/plugins/data/public/ui/dataset_selector/index.tsx b/src/plugins/data/public/ui/dataset_selector/index.tsx new file mode 100644 index 000000000000..c5c2835fe6ef --- /dev/null +++ b/src/plugins/data/public/ui/dataset_selector/index.tsx @@ -0,0 +1,49 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { useEffect, useState } from 'react'; +import React from 'react'; +import { Dataset, Query, TimeRange } from '../../../common'; +import { DatasetSelector } from './dataset_selector'; +import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; +import { IDataPluginServices } from '../../types'; + +interface ConnectedDatasetSelectorProps { + onSubmit: ((query: Query, dateRange?: TimeRange | undefined) => void) | undefined; +} + +const ConnectedDatasetSelector = ({ onSubmit }: ConnectedDatasetSelectorProps) => { + const { services } = useOpenSearchDashboards(); + const queryString = services.data.query.queryString; + const initialDataset = queryString.getQuery().dataset || queryString.getDefaultQuery().dataset; + const [selectedDataset, setSelectedDataset] = useState(initialDataset); + + useEffect(() => { + const subscription = queryString.getUpdates$().subscribe((query) => { + setSelectedDataset(query.dataset); + }); + + return () => subscription.unsubscribe(); + }, [queryString]); + + const handleDatasetChange = (dataset?: Dataset) => { + setSelectedDataset(dataset); + if (dataset) { + const query = queryString.getInitialQueryByDataset(dataset); + queryString.setQuery(query); + onSubmit!(queryString.getQuery()); + } + }; + + return ( + + ); +}; + +export { ConnectedDatasetSelector as DatasetSelector }; diff --git a/src/plugins/data/public/ui/index.ts b/src/plugins/data/public/ui/index.ts index 9259a34fad79..a5ee305d0b53 100644 --- a/src/plugins/data/public/ui/index.ts +++ b/src/plugins/data/public/ui/index.ts @@ -28,14 +28,7 @@ * under the License. */ -export { - UiEnhancements, - IUiStart, - IUiSetup, - createSettings, - Settings, - DataSettings, -} from './types'; +export { UiEnhancements, IUiStart, IUiSetup } from './types'; export { IndexPatternSelectProps } from './index_pattern_select'; export { FilterLabel } from './filter_bar'; export { QueryStringInput, QueryStringInputProps } from './query_string_input'; @@ -46,12 +39,15 @@ export { QueryEditorExtensions, QueryEditorExtensionDependencies, QueryEditorExtensionConfig, + createEditor, + DefaultInput, + DQLBody, + SingleLineInput, } from './query_editor'; -export { SearchBar, SearchBarProps, StatefulSearchBarProps } from './search_bar'; -export { SuggestionsComponent } from './typeahead'; export { - DataSetNavigator, - setAsyncSessionId, - getAsyncSessionId, - setAsyncSessionIdByObj, -} from './dataset_navigator'; + SearchBar, + SearchBarProps, + StatefulSearchBarProps, + useQueryStringManager, +} from './search_bar'; +export { SuggestionsComponent } from './typeahead'; diff --git a/src/plugins/data/public/ui/mocks.ts b/src/plugins/data/public/ui/mocks.ts index dc70e5cac1d4..c6923394b22c 100644 --- a/src/plugins/data/public/ui/mocks.ts +++ b/src/plugins/data/public/ui/mocks.ts @@ -3,27 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Observable } from 'rxjs'; -import { SettingsMock } from './settings/mocks'; import { IUiSetup, IUiStart } from './types'; -import { ISearchStart } from '../search/types'; - -const createMockWebStorage = () => ({ - clear: jest.fn(), - getItem: jest.fn(), - key: jest.fn(), - removeItem: jest.fn(), - setItem: jest.fn(), - length: 0, -}); - -const createMockStorage = () => ({ - storage: createMockWebStorage(), - get: jest.fn(), - set: jest.fn(), - remove: jest.fn(), - clear: jest.fn(), -}); function createSetupContract(): jest.Mocked { return { @@ -31,24 +11,11 @@ function createSetupContract(): jest.Mocked { }; } -function createStartContract( - isEnhancementsEnabled: boolean = false, - searchServiceMock: jest.Mocked -): jest.Mocked { - const queryEnhancements = new Map(); +function createStartContract(): jest.Mocked { return { IndexPatternSelect: jest.fn(), - DataSetNavigator: jest.fn(), // Add the missing property SearchBar: jest.fn(), - SuggestionsComponent: jest.fn(), // Add the missing property - Settings: new SettingsMock( - { supportedAppNames: ['discover'] }, - searchServiceMock, - createMockStorage(), - queryEnhancements, - {} // Add the missing argument here - ), - dataSetContainer$: new Observable(), + SuggestionsComponent: jest.fn(), }; } diff --git a/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap b/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap index 4fa0dc9b33e7..fd8aa75f7344 100644 --- a/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap +++ b/src/plugins/data/public/ui/query_editor/__snapshots__/language_selector.test.tsx.snap @@ -481,8 +481,13 @@ exports[`LanguageSelector should select DQL if language is kuery 1`] = ` } > * { + flex: 0 1 auto; + min-width: 0; + } + .osdQueryEditor__collapseBtn { padding-right: $euiSizeXS; border-right: $euiBorderThin; diff --git a/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx b/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx index 121049d36f13..6c5c52bf6a10 100644 --- a/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx +++ b/src/plugins/data/public/ui/query_editor/editors/default_editor/index.tsx @@ -27,7 +27,7 @@ interface DefaultInputProps extends React.JSX.IntrinsicAttributes { provideCompletionItems: monaco.languages.CompletionItemProvider['provideCompletionItems']; } -const DefaultInput: React.FC = ({ +export const DefaultInput: React.FC = ({ languageId, value, onChange, diff --git a/src/plugins/data/public/ui/query_editor/editors/dql_editor/index.tsx b/src/plugins/data/public/ui/query_editor/editors/dql_editor/index.tsx index b60ca7ee413b..30eea1ee1489 100644 --- a/src/plugins/data/public/ui/query_editor/editors/dql_editor/index.tsx +++ b/src/plugins/data/public/ui/query_editor/editors/dql_editor/index.tsx @@ -10,6 +10,6 @@ interface DQLBodyProps extends React.JSX.IntrinsicAttributes { filterBar?: any; } -const DQLBody: React.FC = ({ filterBar }) =>
{filterBar}
; +export const DQLBody: React.FC = ({ filterBar }) =>
{filterBar}
; export const createDQLEditor = createEditor(SingleLineInput, SingleLineInput, DQLBody); diff --git a/src/plugins/data/public/ui/query_editor/editors/shared.tsx b/src/plugins/data/public/ui/query_editor/editors/shared.tsx index ac41add330ee..23b46c22a48c 100644 --- a/src/plugins/data/public/ui/query_editor/editors/shared.tsx +++ b/src/plugins/data/public/ui/query_editor/editors/shared.tsx @@ -27,7 +27,7 @@ export interface Editor { Body: BodyComponent
@@ -444,7 +444,7 @@ exports[`WorkspaceList should render title and table normally 1`] = ` class="euiToolTipAnchor" >
should be able to see the description tooltip when hovering over the description @@ -655,7 +655,7 @@ exports[`WorkspaceList should render title and table normally 1`] = ` class="euiToolTipAnchor" >
should be able to see the description tooltip when hovering over the description @@ -833,7 +833,7 @@ exports[`WorkspaceList should render title and table normally 1`] = ` class="euiToolTipAnchor" >
diff --git a/src/plugins/workspace/public/components/workspace_list/index.tsx b/src/plugins/workspace/public/components/workspace_list/index.tsx index ab38ce7e6a88..88e80609a410 100644 --- a/src/plugins/workspace/public/components/workspace_list/index.tsx +++ b/src/plugins/workspace/public/components/workspace_list/index.tsx @@ -327,7 +327,7 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { data-test-subj="workspaceList-hover-description" > {/* Here I need to set width mannuly as the tooltip will ineffect the property : truncateText ', */} - + {description} @@ -379,7 +379,7 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { iconType="copy" color="text" > - Copy ID + Copy ID ); }, @@ -400,7 +400,7 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { size="xs" color="text" > - Edit + Edit ); }, @@ -416,11 +416,12 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { onClick={() => { setDeletedWorkspaces([item]); }} - size="xs" + size="s" iconType="trash" color="danger" + style={{ padding: 0 }} > - Delete + Delete ); }, @@ -445,11 +446,12 @@ export const WorkspaceList = ({ registeredUseCases$ }: WorkspaceListProps) => { Date: Fri, 30 Aug 2024 10:42:49 -0700 Subject: [PATCH 269/276] [Page Header]Implement new page header for admin data sources page (#7833) (#7945) * Implement new page header for admin data sources page * update unit tests for page header change * make button group smaller and change section title to h2 --------- (cherry picked from commit cb273fcbf908b631b665a232fb6f9d485489a010) Signed-off-by: Wei Wang Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: Wei Wang --- .../opensearch_dashboards.json | 2 +- .../public/components/breadcrumbs.ts | 12 +- .../create_form/create_data_source_form.tsx | 36 +++++- .../components/header/header.tsx | 1 + .../create_data_source_wizard.tsx | 8 +- .../create_data_source_panel.test.tsx | 3 +- .../create_data_source_panel.tsx | 37 +++++- .../data_source_home_panel.test.tsx.snap | 3 - .../data_source_home_panel.test.tsx | 12 +- .../data_source_home_panel.tsx | 119 +++++++++++++++--- .../data_source_table.test.tsx.snap | 19 +-- .../data_source_table/data_source_table.tsx | 1 + .../direct_query_connection_detail.tsx | 20 ++- ...query_data_connections_table.test.tsx.snap | 3 - ...ge_direct_query_data_connections_table.tsx | 1 - .../query_permissions.test.tsx.snap | 10 +- ...figure_amazon_s3_data_source.test.tsx.snap | 43 ++++--- .../configure_amazon_s3_data_source.tsx | 96 ++++++++++---- .../configure_direct_query_data_sources.tsx | 101 ++++----------- ...igure_prometheus_data_source.test.tsx.snap | 68 +++++----- .../configure_prometheus_data_source.tsx | 58 ++++++--- .../query_permissions.tsx | 4 +- .../edit_form/edit_data_source_form.tsx | 62 +++++---- .../components/header/header.tsx | 42 ++++++- .../edit_data_source.test.tsx | 7 +- .../edit_data_source/edit_data_source.tsx | 5 + .../mount_management_section.test.tsx | 24 +++- .../mount_management_section.tsx | 25 +++- .../data_source_management/public/types.ts | 2 + 29 files changed, 549 insertions(+), 275 deletions(-) diff --git a/src/plugins/data_source_management/opensearch_dashboards.json b/src/plugins/data_source_management/opensearch_dashboards.json index fb37a16eea0f..86f5d0b5d11f 100644 --- a/src/plugins/data_source_management/opensearch_dashboards.json +++ b/src/plugins/data_source_management/opensearch_dashboards.json @@ -3,7 +3,7 @@ "version": "opensearchDashboards", "server": true, "ui": true, - "requiredPlugins": ["management", "indexPatternManagement"], + "requiredPlugins": ["navigation", "management", "indexPatternManagement"], "optionalPlugins": ["dataSource"], "requiredBundles": ["opensearchDashboardsReact", "dataSource", "opensearchDashboardsUtils"], "extraPublicDirs": ["public/components/utils"], diff --git a/src/plugins/data_source_management/public/components/breadcrumbs.ts b/src/plugins/data_source_management/public/components/breadcrumbs.ts index e1ac30bddb88..0980e931d5fb 100644 --- a/src/plugins/data_source_management/public/components/breadcrumbs.ts +++ b/src/plugins/data_source_management/public/components/breadcrumbs.ts @@ -28,14 +28,14 @@ export function getCreateBreadcrumbs() { }, ]; } -export function getCreateOpenSearchDataSourceBreadcrumbs() { +export function getCreateOpenSearchDataSourceBreadcrumbs(useNewUX: boolean) { return [ ...getCreateBreadcrumbs(), { text: i18n.translate( 'dataSourcesManagement.dataSources.createOpenSearchDataSourceBreadcrumbs', { - defaultMessage: 'Open Search', + defaultMessage: useNewUX ? 'Connect OpenSearch Cluster' : 'Open Search', } ), href: `/configure/OpenSearch`, @@ -43,14 +43,14 @@ export function getCreateOpenSearchDataSourceBreadcrumbs() { ]; } -export function getCreateAmazonS3DataSourceBreadcrumbs() { +export function getCreateAmazonS3DataSourceBreadcrumbs(useNewUX: boolean) { return [ ...getCreateBreadcrumbs(), { text: i18n.translate( 'dataSourcesManagement.dataSources.createAmazonS3DataSourceBreadcrumbs', { - defaultMessage: 'Amazon S3', + defaultMessage: useNewUX ? 'Connect Amazon S3' : 'Amazon S3', } ), href: `/configure/AmazonS3AWSGlue`, @@ -58,14 +58,14 @@ export function getCreateAmazonS3DataSourceBreadcrumbs() { ]; } -export function getCreatePrometheusDataSourceBreadcrumbs() { +export function getCreatePrometheusDataSourceBreadcrumbs(useNewUX: boolean) { return [ ...getCreateBreadcrumbs(), { text: i18n.translate( 'dataSourcesManagement.dataSources.createPrometheusDataSourceBreadcrumbs', { - defaultMessage: 'Prometheus', + defaultMessage: useNewUX ? 'Connect Prometheus' : 'Prometheus', } ), href: `/configure/Prometheus`, 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 7fec74bdc0f9..f2eb7778e8e7 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 @@ -23,6 +23,8 @@ import { } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; +import { NavigationPublicPluginStart } from 'src/plugins/navigation/public'; +import { ApplicationStart } from 'opensearch-dashboards/public'; import { AuthenticationMethodRegistry } from '../../../../auth_registry'; import { SigV4Content, SigV4ServiceName } from '../../../../../../data_source/common/data_sources'; import { @@ -47,6 +49,9 @@ import { } from '../../../utils'; export interface CreateDataSourceProps { + useNewUX: boolean; + navigation: NavigationPublicPluginStart; + application: ApplicationStart; existingDatasourceNamesList: string[]; handleSubmit: (formValues: DataSourceAttributes) => void; handleTestConnection: (formValues: DataSourceAttributes) => void; @@ -367,21 +372,41 @@ export class CreateDataSourceForm extends React.Component< return null; }; + description = [ + { + renderComponent: ( + + + + ), + }, + ]; + /* Render methods */ /* Render header*/ renderHeader = () => { - return
; + return this.props.useNewUX ? ( + + ) : ( +
+ ); }; /* Render Section header*/ renderSectionHeader = (i18nId: string, defaultMessage: string) => { return ( <> - -

+ +

-

+

); @@ -554,7 +579,6 @@ export class CreateDataSourceForm extends React.Component< <> {this.renderHeader()} - {/* Endpoint section */} {this.renderSectionHeader( @@ -749,7 +773,7 @@ export class CreateDataSourceForm extends React.Component< > diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/header/header.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/header/header.tsx index 75eda9af9809..c6caa900b436 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/components/header/header.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/components/header/header.tsx @@ -45,6 +45,7 @@ export const Header = () => {

+
diff --git a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx index 0be281a20a38..e589d4fee72a 100644 --- a/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx +++ b/src/plugins/data_source_management/public/components/create_data_source_wizard/create_data_source_wizard.tsx @@ -37,15 +37,18 @@ export const CreateDataSourceWizard: React.FunctionComponent().services; /* State Variables */ const [existingDatasourceNamesList, setExistingDatasourceNamesList] = useState([]); const [isLoading, setIsLoading] = useState(false); + const useNewUX = uiSettings.get('home:useNewHomePage'); /* Set breadcrumb */ useEffectOnce(() => { - setBreadcrumbs(getCreateOpenSearchDataSourceBreadcrumbs()); + setBreadcrumbs(getCreateOpenSearchDataSourceBreadcrumbs(useNewUX)); getExistingDataSourceNames(); }); @@ -128,6 +131,9 @@ export const CreateDataSourceWizard: React.FunctionComponent props.history.push('/create')} diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx index 5884dadc5876..235446ffbfea 100644 --- a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.test.tsx @@ -10,8 +10,8 @@ import { CreateDataSourcePanelHeader } from './create_data_source_panel_header'; import { CreateDataSourceCardView } from './create_data_source_card_view'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; import { getCreateBreadcrumbs } from '../breadcrumbs'; -import { DataSourceManagementContext } from '../../types'; import { RouteComponentProps } from 'react-router-dom'; +import { navigationPluginMock } from 'src/plugins/navigation/public/mocks'; jest.mock('../../../../opensearch_dashboards_react/public'); jest.mock('../breadcrumbs'); @@ -34,6 +34,7 @@ describe('CreateDataSourcePanel', () => { }, }, uiSettings: {}, + navigation: navigationPluginMock.createStartContract(), }, }; diff --git a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx index 7e6761d51254..8228c82e4ca1 100644 --- a/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx +++ b/src/plugins/data_source_management/public/components/data_source_creation_panel/create_data_source_panel.tsx @@ -3,9 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiFlexGroup, EuiFlexItem, EuiPageHeader, EuiPanel } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiPageHeader, EuiPanel, EuiText } from '@elastic/eui'; import React, { useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; +import { FormattedMessage } from '@osd/i18n/react'; import { CreateDataSourcePanelHeader } from './create_data_source_panel_header'; import { CreateDataSourceCardView } from './create_data_source_card_view'; import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public'; @@ -14,24 +15,56 @@ import { DataSourceManagementContext } from '../../types'; interface CreateDataSourcePanelProps extends RouteComponentProps { featureFlagStatus: boolean; + useNewUX: boolean; } export const CreateDataSourcePanel: React.FC = ({ featureFlagStatus, + useNewUX, ...props }) => { const { chrome, + application, setBreadcrumbs, notifications: { toasts }, uiSettings, + navigation, } = useOpenSearchDashboards().services; useEffect(() => { setBreadcrumbs(getCreateBreadcrumbs()); }, [setBreadcrumbs]); - return ( + const { HeaderControl } = navigation.ui; + const description = [ + { + renderComponent: ( + + + + ), + }, + ]; + + return useNewUX ? ( + <> + + + + + + + + + + ) : ( diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap index e4144646e0b0..cda3acc64031 100644 --- a/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/__snapshots__/data_source_home_panel.test.tsx.snap @@ -61,9 +61,6 @@ exports[`DataSourceHomePanel renders correctly 1`] = ` - { savedObjects: {}, uiSettings: {}, application: { capabilities: { dataSource: { canManage: true } } }, + docLinks: { + links: { + opensearchDashboards: { + dataSource: { + guide: 'https://opensearch.org/docs/latest/dashboards/discover/multi-data-sources/', + }, + }, + }, + }, + navigation: navigationPluginMock.createStartContract(), }, }; diff --git a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx index 3291885a8b60..dfb3fc0ae188 100644 --- a/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx +++ b/src/plugins/data_source_management/public/components/data_source_home_panel/data_source_home_panel.tsx @@ -13,7 +13,12 @@ import { EuiTab, EuiPageHeader, EuiPanel, + EuiButtonGroup, + EuiText, + EuiLink, } from '@elastic/eui'; +import { TopNavControlButtonData, TopNavControlComponentData } from 'src/plugins/navigation/public'; +import { FormattedMessage } from '@osd/i18n/react'; import { DataSourceHeader } from './data_source_page_header'; import { DataSourceTableWithRouter } from '../data_source_table/data_source_table'; import { ManageDirectQueryDataConnectionsTable } from '../direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table'; @@ -24,10 +29,12 @@ import { DataSourceManagementContext } from '../../types'; interface DataSourceHomePanelProps extends RouteComponentProps { featureFlagStatus: boolean; + useNewUX: boolean; } export const DataSourceHomePanel: React.FC = ({ featureFlagStatus, + useNewUX, ...props }) => { const { @@ -37,6 +44,8 @@ export const DataSourceHomePanel: React.FC = ({ savedObjects, uiSettings, application, + docLinks, + navigation, } = useOpenSearchDashboards().services; const defaultTabId = featureFlagStatus @@ -44,6 +53,7 @@ export const DataSourceHomePanel: React.FC = ({ : 'manageDirectQueryDataSources'; const [selectedTabId, setSelectedTabId] = useState(defaultTabId); const canManageDataSource = !!application.capabilities?.dataSource?.canManage; + const { HeaderControl } = navigation.ui; useEffect(() => { setBreadcrumbs(getListBreadcrumbs()); @@ -53,6 +63,56 @@ export const DataSourceHomePanel: React.FC = ({ setSelectedTabId(id); }; + const description = [ + { + renderComponent: ( + + + + Learn more + + + ), + }, + ]; + + const createDataSourceButton = [ + { + id: 'Create data source', + label: 'Create data source connection', + testId: 'createDataSourceButton', + run: () => props.history.push('/create'), + fill: true, + iconType: 'plus', + controlType: 'button', + } as TopNavControlButtonData, + ]; + + const connectionTypeButton = [ + { + renderComponent: ( + onSelectedTabChanged(id)} + /> + ), + } as TopNavControlComponentData, + ]; + const tabs = [ ...(featureFlagStatus ? [ @@ -82,27 +142,48 @@ export const DataSourceHomePanel: React.FC = ({ return ( + {useNewUX && ( + <> + + {canManageDataSource && ( + + )} + + + )} + {!useNewUX && ( + <> + + + + + + + {canManageDataSource ? ( + + + + ) : null} + + + + + + {renderTabs()} + + + )} - - - - - - {canManageDataSource ? ( - - - - ) : null} - - - - - - {renderTabs()} - - - {selectedTabId === 'manageOpensearchDataSources' && featureFlagStatus && ( )} diff --git a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap index 3f12831b546b..9dc785b13b4e 100644 --- a/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/data_source_table/__snapshots__/data_source_table.test.tsx.snap @@ -369,6 +369,7 @@ exports[`DataSourceTable should get datasources successful should render normall }, }, }, + "compressed": true, "toolsRight": @@ -416,6 +417,7 @@ exports[`DataSourceTable should get datasources successful should render normall }, } } + compressed={true} onChange={[Function]} toolsRight={
@@ -504,7 +507,7 @@ exports[`DataSourceTable should get datasources successful should render normall className="euiFormControlLayoutIcons" >
-
diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx index 1df5b7b87bb8..9d38347f3dac 100644 --- a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_connection/manage_direct_query_data_connections_table.tsx @@ -331,7 +331,6 @@ export const ManageDirectQueryDataConnectionsTable: React.FC - {customSearchBar} diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap index 36b12e2b510c..ec2445107be8 100644 --- a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/__snapshots__/query_permissions.test.tsx.snap @@ -34,13 +34,15 @@ exports[`QueryPermissionsConfiguration renders correctly 1`] = `
- +
-

+

Query permissions -

+
- Connect to Amazon S3 via AWS Glue Data Catalog with Amazon EMR as an execution engine. + Make sure you connected to Amazon S3 via AWS Glue Data Catalog with Amazon EMR as an execution engine.
@@ -236,18 +236,21 @@ exports[`ConfigureS3DatasourcePanel renders correctly 1`] = `
+
- +
-

+

Data source details -

+
- +
-

+

AWS Glue Data Catalog authentication details -

+
- +
-

+

AWS Glue Data Catalog index store details -

+
- +
-

+

Query permissions -

+
>; @@ -49,6 +54,9 @@ interface ConfigureS3DatasourceProps extends RouteComponentProps { export const ConfigureS3DatasourcePanel: React.FC = (props) => { const { + useNewUX, + navigation, + application, setNameForRequest, setDetailsForRequest, setArnForRequest, @@ -83,30 +91,68 @@ export const ConfigureS3DatasourcePanel: React.FC = { value: 'noauth', text: 'No authentication' }, ]; + const description = [ + { + renderComponent: ( + + + {docLinks && ( + + Learn more + + )} + + ), + }, + ]; + + const callOut = ( + + + {`Make sure you connected to Amazon S3 via AWS Glue Data Catalog with Amazon EMR as an execution engine. `} + {docLinks && ( + + Learn more + + )} + + + ); + return (
+ {!useNewUX &&

{`Configure Amazon S3 data source`}

}
+ {useNewUX ? ( + <> + + + + ) : ( + <> + + {callOut} + + )} -

{`Configure Amazon S3 data source`}

-
- - - - {`Connect to Amazon S3 via AWS Glue Data Catalog with Amazon EMR as an execution engine. `} - {docLinks && ( - - Learn more - - )} - - - - -

Data source details

+

Data source details

= - -

AWS Glue Data Catalog authentication details

+ +

AWS Glue Data Catalog authentication details

@@ -171,8 +217,8 @@ export const ConfigureS3DatasourcePanel: React.FC = - -

AWS Glue Data Catalog index store details

+ +

AWS Glue Data Catalog index store details

diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/configure_direct_query_data_sources.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/configure_direct_query_data_sources.tsx index 11201fe9d538..a45e853de2d9 100644 --- a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/configure_direct_query_data_sources.tsx +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/configure_direct_query_data_sources.tsx @@ -8,19 +8,15 @@ import { EuiFlexItem, EuiPage, EuiPageBody, - EuiSpacer, - EuiSteps, - EuiPageSideBar, EuiBottomBar, EuiButtonEmpty, EuiButton, + EuiSpacer, } from '@elastic/eui'; import React, { useEffect, useState, useCallback } from 'react'; import { RouteComponentProps, useParams, withRouter } from 'react-router-dom'; import { ConfigureS3DatasourcePanel } from './amazon_s3/configure_amazon_s3_data_source'; import { ConfigurePrometheusDatasourcePanel } from './prometheus/configure_prometheus_data_source'; -import { ReviewS3Datasource } from './amazon_s3/review_amazon_s3_data_source'; -import { ReviewPrometheusDatasource } from './prometheus/review_prometheus_data_source'; import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; import { DataSourceManagementContext, DirectQueryDatasourceType, Role } from '../../../types'; import { DatasourceTypeToDisplayName, UrlToDatasourceType } from '../../../constants'; @@ -35,10 +31,12 @@ import { DATACONNECTIONS_BASE } from '../../../constants'; interface ConfigureDatasourceProps extends RouteComponentProps { notifications: NotificationsStart; + useNewUX: boolean; } export const DirectQueryDataSourceConfigure: React.FC = ({ notifications, + useNewUX, history, }) => { const { type: urlType } = useParams<{ type: string }>(); @@ -47,6 +45,8 @@ export const DirectQueryDataSourceConfigure: React.FC setBreadcrumbs, notifications: { toasts }, http, + navigation, + application, } = useOpenSearchDashboards().services; const [error, setError] = useState(''); @@ -63,17 +63,7 @@ export const DirectQueryDataSourceConfigure: React.FC const [roles, setRoles] = useState([]); const [hasSecurityAccess, setHasSecurityAccess] = useState(true); const [selectedQueryPermissionRoles, setSelectedQueryPermissionRoles] = useState([]); - const [page, setPage] = useState<'configure' | 'review'>('configure'); const type = UrlToDatasourceType[urlType]; - const ConfigureDatasourceSteps = [ - { - title: 'Configure data source', - status: page === 'review' ? 'complete' : undefined, - }, - { - title: 'Review configuration', - }, - ]; const formatError = (errorName: string, errorMessage: string, errorDetails: string) => { return { @@ -159,7 +149,6 @@ export const DirectQueryDataSourceConfigure: React.FC notifications.toasts.addError(formattedError, { title: 'Could not create data source', }); - setPage('configure'); }); }, [ authMethod, @@ -196,16 +185,16 @@ export const DirectQueryDataSourceConfigure: React.FC let breadcrumbs; switch (urlType) { case 'AmazonS3AWSGlue': - breadcrumbs = getCreateAmazonS3DataSourceBreadcrumbs(); + breadcrumbs = getCreateAmazonS3DataSourceBreadcrumbs(useNewUX); break; case 'Prometheus': - breadcrumbs = getCreatePrometheusDataSourceBreadcrumbs(); + breadcrumbs = getCreatePrometheusDataSourceBreadcrumbs(useNewUX); break; default: breadcrumbs = getCreateBreadcrumbs(); } setBreadcrumbs(breadcrumbs); - }, [urlType, setBreadcrumbs, http]); + }, [urlType, setBreadcrumbs, http, useNewUX]); const ConfigureDatasource = (configurationProps: { datasourceType: DirectQueryDatasourceType; @@ -215,6 +204,9 @@ export const DirectQueryDataSourceConfigure: React.FC case 'S3GLUE': return ( case 'PROMETHEUS': return ( } }; - const ReviewDatasourceConfiguration = (configurationProps: { datasourceType: string }) => { - const { datasourceType } = configurationProps; - switch (datasourceType) { - case 'S3GLUE': - return ( - setPage('configure')} - /> - ); - case 'PROMETHEUS': - return ( - setPage('configure')} - /> - ); - default: - return <>; - } - }; - const ReviewSaveOrCancel = useCallback(() => { return ( @@ -324,44 +286,25 @@ export const DirectQueryDataSourceConfigure: React.FC setPage('configure')} - color="ghost" - size="s" - iconType="arrowLeft" - data-test-subj="previousButton" - > - Previous - - - - (page === 'review' ? createDatasource() : setPage('review'))} + onClick={() => createDatasource()} size="s" - iconType="arrowRight" + iconType="check" + color="secondary" fill - data-test-subj="nextButton" + data-test-subj="createButton" > - {page === 'configure' - ? `Review Configuration` - : `Connect to ${DatasourceTypeToDisplayName[type]}`} + {`Connect to ${DatasourceTypeToDisplayName[type]}`} ); - }, [page, history, createDatasource, type]); + }, [history, createDatasource, type]); return ( - - - - + - {page === 'configure' ? ( - - ) : ( - - )} + diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/__snapshots__/configure_prometheus_data_source.test.tsx.snap b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/__snapshots__/configure_prometheus_data_source.test.tsx.snap index 2032dacce601..e630120bf7cc 100644 --- a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/__snapshots__/configure_prometheus_data_source.test.tsx.snap +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/prometheus/__snapshots__/configure_prometheus_data_source.test.tsx.snap @@ -106,17 +106,25 @@ exports[`ConfigurePrometheusDatasourcePanel renders correctly 1`] = `
@@ -161,13 +157,15 @@ exports[`ConfigurePrometheusDatasourcePanel renders correctly 1`] = ` - +
-

+

Data source details -

+
- +
-

+

Prometheus data location -

+
- +
-

+

Authentication details -

+
- +
-

+

Query permissions -

+
>; @@ -51,6 +56,9 @@ interface ConfigurePrometheusDatasourceProps { export const ConfigurePrometheusDatasourcePanel = (props: ConfigurePrometheusDatasourceProps) => { const { + useNewUX, + navigation, + application, setNameForRequest, setDetailsForRequest, setStoreForRequest, @@ -84,23 +92,37 @@ export const ConfigurePrometheusDatasourcePanel = (props: ConfigurePrometheusDat { value: 'awssigv4', text: 'AWS Signature Version 4' }, ]; + const description = ( + + + + Learn more + + + ); + return (
- -

{`Configure Prometheus data source`}

-
- - - {`Connect to Prometheus with OpenSearch and OpenSearch Dashboards. `} - - Learn more - - - + {!useNewUX &&

{`Configure Prometheus data source`}

}
+ {useNewUX ? ( + + ) : ( + <> + + {description} + + + )} - -

Data source details

+ +

Data source details

- -

Prometheus data location

+ +

Prometheus data location

@@ -149,8 +171,8 @@ export const ConfigurePrometheusDatasourcePanel = (props: ConfigurePrometheusDat - -

Authentication details

+ +

Authentication details

diff --git a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/query_permissions.tsx b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/query_permissions.tsx index 26570bae318b..c6e7a64604bd 100644 --- a/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/query_permissions.tsx +++ b/src/plugins/data_source_management/public/components/direct_query_data_sources_components/direct_query_data_source_configuration/query_permissions.tsx @@ -70,8 +70,8 @@ export const QueryPermissionsConfiguration = (props: PermissionsConfigurationPro - -

Query permissions

+ +

Query permissions

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 48e40dbfd88f..125539a4dfc5 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 @@ -26,6 +26,8 @@ import { import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; import deepEqual from 'fast-deep-equal'; +import { ApplicationStart } from 'opensearch-dashboards/public'; +import { NavigationPublicPluginStart } from 'src/plugins/navigation/public'; import { AuthenticationMethodRegistry } from '../../../../auth_registry'; import { SigV4Content, SigV4ServiceName } from '../../../../../../data_source/common/data_sources'; import { Header } from '../header'; @@ -49,6 +51,9 @@ import { UpdateAwsCredentialModal } from '../update_aws_credential_modal'; import { extractRegisteredAuthTypeCredentials, getDefaultAuthMethod } from '../../../utils'; export interface EditDataSourceProps { + navigation: NavigationPublicPluginStart; + application: ApplicationStart; + useNewUX: boolean; existingDataSource: DataSourceAttributes; existingDatasourceNamesList: string[]; isDefault: boolean; @@ -643,6 +648,9 @@ export class EditDataSourceForm extends React.Component { return (

{ return ( - -

+ +

{ } -

+

- { - - } - + +

+ { + + } +

+
} description={

@@ -763,15 +773,15 @@ export class EditDataSourceForm extends React.Component { return ( - -

+ +

{ } -

+

@@ -799,29 +809,31 @@ export class EditDataSourceForm extends React.Component { return ( - -

+ +

{ } -

+

- { - - } - + +

+ { + + } +

+
} > {this.renderCredentialsSection()} diff --git a/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.tsx b/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.tsx index 3e76ab838f9d..6775c659e6c1 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/components/header/header.tsx @@ -18,10 +18,18 @@ import { } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { FormattedMessage } from '@osd/i18n/react'; +import { + NavigationPublicPluginStart, + TopNavControlComponentData, +} from 'src/plugins/navigation/public'; +import { ApplicationStart } from 'opensearch-dashboards/public'; import { useOpenSearchDashboards } from '../../../../../../opensearch_dashboards_react/public'; import { DataSourceManagementContext } from '../../../../types'; export const Header = ({ + navigation, + application, + useNewUX, showDeleteIcon, isFormValid, onClickDeleteIcon, @@ -31,6 +39,9 @@ export const Header = ({ isDefault, canManageDataSource, }: { + navigation: NavigationPublicPluginStart; + application: ApplicationStart; + useNewUX: boolean; showDeleteIcon: boolean; isFormValid: boolean; onClickDeleteIcon: () => void; @@ -67,6 +78,7 @@ export const Header = ({ iconType={isDefaultDataSourceState ? 'starFilled' : 'starEmpty'} aria-label={setDefaultAriaLabel} data-test-subj="editSetDefaultDataSource" + iconSize="s" > {isDefaultDataSourceState ? 'Default' : 'Set as default'} @@ -88,14 +100,13 @@ export const Header = ({ setIsDeleteModalVisible(true); }} iconType="trash" - iconSize="m" - size="m" aria-label={i18n.translate( 'dataSourcesManagement.editDataSource.deleteThisDataSource', { defaultMessage: 'Delete this Data Source', } )} + iconSize="s" /> @@ -154,6 +165,7 @@ export const Header = ({ onClickTestConnection(); }} data-test-subj="datasource-edit-testConnectionButton" + iconSize="s" > + + {/* Test default button */} + {renderDefaultIcon()} + {/* Test connection button */} + {renderTestConnectionButton()} + {/* Delete icon button */} + {canManageDataSource ? ( + {showDeleteIcon ? renderDeleteButton() : null} + ) : null} + + + ), + } as TopNavControlComponentData, + ]; + + return useNewUX ? ( + + ) : ( {/* Title */} diff --git a/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.test.tsx b/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.test.tsx index f53744d67716..9645443ff1dd 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.test.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.test.tsx @@ -142,7 +142,12 @@ describe('Datasource Management: Edit Datasource Wizard', () => { test('should delete datasource successfully', async () => { spyOn(utils, 'deleteDataSourceById').and.returnValue({}); spyOn(utils, 'setFirstDataSourceAsDefault').and.returnValue({}); - spyOn(uiSettings, 'get').and.returnValue('test1'); + spyOn(uiSettings, 'get').and.callFake((key) => { + if (key === 'home:useNewHomePage') { + return false; + } + return 'test1'; + }); await act(async () => { // @ts-ignore await component.find(formIdentifier).first().prop('onDeleteDataSource')( diff --git a/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.tsx b/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.tsx index fbf63aaecb0d..5163506c9e3a 100644 --- a/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.tsx +++ b/src/plugins/data_source_management/public/components/edit_data_source/edit_data_source.tsx @@ -47,6 +47,7 @@ export const EditDataSource: React.FunctionComponent().services; const dataSourceID: string = props.match.params.id; @@ -54,6 +55,7 @@ export const EditDataSource: React.FunctionComponent(defaultDataSource); const [existingDatasourceNamesList, setExistingDatasourceNamesList] = useState([]); const [isLoading, setIsLoading] = useState(false); + const useNewUX = uiSettings.get('home:useNewHomePage'); /* Fetch data source by id*/ useEffectOnce(() => { @@ -155,6 +157,9 @@ export const EditDataSource: React.FunctionComponent {dataSource && dataSource.endpoint ? ( { + if (key === 'home:useNewHomePage') { + return false; + } + return 'default'; + }), + }, notifications: {}, overlays: {}, http: {}, docLinks: {}, }, + { + navigation: {}, + }, ]); const mockParams: any = { @@ -128,12 +138,22 @@ describe('mountManagementSection', () => { chrome: { docTitle: { reset: jest.fn() } }, application: { capabilities: { dataSource: { canManage: false } } }, savedObjects: {}, - uiSettings: {}, + uiSettings: { + get: jest.fn((key) => { + if (key === 'home:useNewHomePage') { + return false; + } + return 'default'; + }), + }, notifications: {}, overlays: {}, http: {}, docLinks: {}, }, + { + navigation: {}, + }, ]); await mountManagementSection(mockGetStartServices, mockParams, mockAuthMethodsRegistry, true); diff --git a/src/plugins/data_source_management/public/management_app/mount_management_section.tsx b/src/plugins/data_source_management/public/management_app/mount_management_section.tsx index c489a6a73936..545a76ec2736 100644 --- a/src/plugins/data_source_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/data_source_management/public/management_app/mount_management_section.tsx @@ -13,6 +13,7 @@ import { DataPublicPluginStart } from 'src/plugins/data/public'; import { EuiPageContent } from '@elastic/eui'; import { ManagementAppMountParams } from '../../../management/public'; +import { NavigationPublicPluginStart } from '../../../navigation/public'; import { OpenSearchDashboardsContextProvider } from '../../../opensearch_dashboards_react/public'; import { CreateDataSourceWizardWithRouter } from '../components/create_data_source_wizard'; import { EditDataSourceWithRouter } from '../components/edit_data_source'; @@ -25,6 +26,7 @@ import { DirectQueryDataConnectionDetail } from '../components/direct_query_data export interface DataSourceManagementStartDependencies { data: DataPublicPluginStart; + navigation: NavigationPublicPluginStart; } export async function mountManagementSection( @@ -35,6 +37,7 @@ export async function mountManagementSection( ) { const [ { chrome, application, savedObjects, uiSettings, notifications, overlays, http, docLinks }, + { navigation }, ] = await getStartServices(); const deps: DataSourceManagementContext = { @@ -46,11 +49,13 @@ export async function mountManagementSection( overlays, http, docLinks, + navigation, setBreadcrumbs: params.setBreadcrumbs, authenticationMethodRegistry: authMethodsRegistry, }; const canManageDataSource = !!application.capabilities?.dataSource?.canManage; + const useNewUX = uiSettings.get('home:useNewHomePage'); const content = ( @@ -62,11 +67,16 @@ export async function mountManagementSection( notifications={notifications} setBreadcrumbs={params.setBreadcrumbs} application={application} + useNewUX={useNewUX} /> {canManageDataSource && ( - + )} {featureFlagStatus && canManageDataSource && ( @@ -76,7 +86,10 @@ export async function mountManagementSection( )} {canManageDataSource && ( - + )} {featureFlagStatus && ( @@ -85,7 +98,11 @@ export async function mountManagementSection( )} - + @@ -95,7 +112,7 @@ export async function mountManagementSection( {params.wrapInPage ? ( - + {content} ) : ( diff --git a/src/plugins/data_source_management/public/types.ts b/src/plugins/data_source_management/public/types.ts index d09591147001..dc3c54505acc 100644 --- a/src/plugins/data_source_management/public/types.ts +++ b/src/plugins/data_source_management/public/types.ts @@ -16,6 +16,7 @@ import { import { ManagementAppMountParams } from 'src/plugins/management/public'; import { i18n } from '@osd/i18n'; import { EuiComboBoxOptionOption } from '@elastic/eui'; +import { NavigationPublicPluginStart } from 'src/plugins/navigation/public'; import { AuthType } from '../../data_source/common/data_sources'; import { SigV4ServiceName } from '../../data_source/common/data_sources'; import { OpenSearchDashboardsReactContextValue } from '../../opensearch_dashboards_react/public'; @@ -33,6 +34,7 @@ export interface DataSourceManagementContext { overlays: OverlayStart; http: HttpSetup; docLinks: DocLinksStart; + navigation: NavigationPublicPluginStart; setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs']; authenticationMethodRegistry: AuthenticationMethodRegistry; } From 0e10ba4d031c0a830c8c466b7413dfb8f19d4672 Mon Sep 17 00:00:00 2001 From: SheyGao <134346934+SheyGao@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:28:30 -0700 Subject: [PATCH 270/276] [VisBuilder-Next] Migrate legacy visualizations to visbuilder by mapping the url (#7529) (#7832) * migration of visualization objects to visbuilder Signed-off-by: Shey Gao * update layover Signed-off-by: Shey Gao * fixed a bug Signed-off-by: Shey Gao * Changeset file for PR #7529 created/updated --------- Signed-off-by: Shey Gao Co-authored-by: Shey Gao Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> (cherry picked from commit 231337231be2ad98f7086b154de43339205f9ca6) --- changelogs/fragments/7529.yml | 2 + .../edit_action_dropdown.test.tsx | 184 ++++++++++++++++++ .../table_list_view/edit_action_dropdown.tsx | 123 ++++++++++++ .../table_list_view/table_list_view.tsx | 30 +-- .../components/data_tab/secondary_panel.tsx | 2 +- .../public/application/utils/breadcrumbs.ts | 12 +- .../application/utils/get_top_nav_config.tsx | 13 +- .../utils/state_management/metadata_slice.ts | 6 +- .../redux_persistence.test.tsx | 1 + .../utils/state_management/store.ts | 2 +- .../application/utils/use/use_can_save.ts | 4 +- .../utils/use/use_saved_vis_builder_vis.ts | 19 +- .../components/visualize_listing.tsx | 14 ++ .../utils/construct_vis_builder_path.ts | 65 +++++++ .../utils/contruct_vis_builder_path.test.ts | 58 ++++++ .../dashboard_listing_plugin.ts | 9 +- 16 files changed, 513 insertions(+), 31 deletions(-) create mode 100644 changelogs/fragments/7529.yml create mode 100644 src/plugins/opensearch_dashboards_react/public/table_list_view/edit_action_dropdown.test.tsx create mode 100644 src/plugins/opensearch_dashboards_react/public/table_list_view/edit_action_dropdown.tsx create mode 100644 src/plugins/visualize/public/application/utils/construct_vis_builder_path.ts create mode 100644 src/plugins/visualize/public/application/utils/contruct_vis_builder_path.test.ts diff --git a/changelogs/fragments/7529.yml b/changelogs/fragments/7529.yml new file mode 100644 index 000000000000..b2031779e48c --- /dev/null +++ b/changelogs/fragments/7529.yml @@ -0,0 +1,2 @@ +feat: +- [VisBuilder-Next] Migration of legacy visualizations to VisBuilder by constructing the URL. ([#7529](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7529)) \ No newline at end of file diff --git a/src/plugins/opensearch_dashboards_react/public/table_list_view/edit_action_dropdown.test.tsx b/src/plugins/opensearch_dashboards_react/public/table_list_view/edit_action_dropdown.test.tsx new file mode 100644 index 000000000000..f6a7cfab2d62 --- /dev/null +++ b/src/plugins/opensearch_dashboards_react/public/table_list_view/edit_action_dropdown.test.tsx @@ -0,0 +1,184 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mount } from 'enzyme'; +import { EditActionDropdown, VisualizationItem } from './edit_action_dropdown'; +import { + EuiContextMenuPanel, + EuiIcon, + EuiPopover, + EuiContextMenuItem, + EuiConfirmModal, +} from '@elastic/eui'; +import { useOpenSearchDashboards } from '../context'; + +// Mock the useOpenSearchDashboards hook +jest.mock('../context', () => ({ + useOpenSearchDashboards: jest.fn(), +})); + +describe('EditActionDropdown', () => { + let component: any; + const mockEditItem = jest.fn(); + const mockVisbuilderEditItem = jest.fn(); + const mockOpenModal = jest.fn(); + const mockCloseModal = jest.fn(); + + const defaultItem: VisualizationItem = { + typeTitle: 'Area', + id: '1', + version: 1, + }; + + const mockOverlays = { + openModal: mockOpenModal.mockReturnValue({ close: mockCloseModal }), + }; + + beforeEach(() => { + // Cast the mocked function to any to avoid TypeScript errors + (useOpenSearchDashboards as jest.Mock).mockReturnValue({ overlays: mockOverlays }); + + component = mount( + + ); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('renders the edit icon', () => { + expect(component.find(EuiIcon).first().prop('type')).toBe('pencil'); + }); + + it('opens the popover when icon is clicked', () => { + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + expect(component.find(EuiPopover).prop('isOpen')).toBe(true); + }); + + it('renders context menu panel with correct options for VisBuilder compatible item', () => { + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + const contextMenuPanel = component.find(EuiContextMenuPanel); + expect(contextMenuPanel.exists()).toBe(true); + expect(contextMenuPanel.prop('items')).toHaveLength(2); + expect(contextMenuPanel.find(EuiContextMenuItem).at(0).text()).toBe('Edit'); + expect(contextMenuPanel.find(EuiContextMenuItem).at(1).text()).toBe('Import to VisBuilder'); + }); + + it('does not render VisBuilder option for incompatible item', () => { + const incompatibleItem: VisualizationItem = { + typeTitle: 'Pie', + id: '2', + version: 2, + }; + component.setProps({ item: incompatibleItem }); + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + const contextMenuPanel = component.find(EuiContextMenuPanel); + expect(contextMenuPanel.prop('items')).toHaveLength(1); + expect(contextMenuPanel.find(EuiContextMenuItem).at(0).text()).toBe('Edit'); + }); + + it('calls editItem when Edit option is clicked', () => { + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + act(() => { + component.find(EuiContextMenuItem).at(0).simulate('click'); + }); + expect(mockEditItem).toHaveBeenCalledWith(defaultItem); + }); + + it('opens a confirmation modal when Import to VisBuilder option is clicked', () => { + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + act(() => { + component.find(EuiContextMenuItem).at(1).simulate('click'); + }); + expect(mockOpenModal).toHaveBeenCalled(); + expect(mockOpenModal.mock.calls[0][0].type).toBe(EuiConfirmModal); + }); + + it('calls visbuilderEditItem when confirmation modal is confirmed', () => { + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + act(() => { + component.find(EuiContextMenuItem).at(1).simulate('click'); + }); + + const modalProps = mockOpenModal.mock.calls[0][0].props; + act(() => { + modalProps.onConfirm(); + }); + + expect(mockVisbuilderEditItem).toHaveBeenCalledWith(defaultItem); + expect(mockCloseModal).toHaveBeenCalled(); + }); + + it('does not call visbuilderEditItem when confirmation modal is cancelled', () => { + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + act(() => { + component.find(EuiContextMenuItem).at(1).simulate('click'); + }); + + const modalProps = mockOpenModal.mock.calls[0][0].props; + act(() => { + modalProps.onCancel(); + }); + + expect(mockVisbuilderEditItem).not.toHaveBeenCalled(); + expect(mockCloseModal).toHaveBeenCalled(); + }); + + it('closes the popover after an action is selected', () => { + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + act(() => { + component.find(EuiContextMenuItem).at(0).simulate('click'); + }); + component.update(); + expect(component.find(EuiPopover).prop('isOpen')).toBe(false); + }); + + it('sets correct props on EuiPopover', () => { + const popover = component.find(EuiPopover); + expect(popover.prop('panelPaddingSize')).toBe('none'); + expect(popover.prop('anchorPosition')).toBe('downLeft'); + expect(popover.prop('initialFocus')).toBe('none'); + }); + + it('sets correct props on EuiContextMenuPanel', () => { + act(() => { + component.find(EuiIcon).first().simulate('click'); + }); + component.update(); + const panel = component.find(EuiContextMenuPanel); + expect(panel.prop('size')).toBe('s'); + }); +}); diff --git a/src/plugins/opensearch_dashboards_react/public/table_list_view/edit_action_dropdown.tsx b/src/plugins/opensearch_dashboards_react/public/table_list_view/edit_action_dropdown.tsx new file mode 100644 index 000000000000..2b155baa0328 --- /dev/null +++ b/src/plugins/opensearch_dashboards_react/public/table_list_view/edit_action_dropdown.tsx @@ -0,0 +1,123 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { useState } from 'react'; +import { + EuiIcon, + EuiPopover, + EuiContextMenuPanel, + EuiContextMenuItem, + EuiText, + EuiConfirmModal, +} from '@elastic/eui'; +import { i18n } from '@osd/i18n'; +import { useOpenSearchDashboards } from '../context'; + +// TODO: include more types once VisBuilder supports more visualization types +const types = ['Area', 'Vertical Bar', 'Line', 'Metric', 'Table']; + +export interface VisualizationItem { + typeTitle: string; + id?: string; + version?: number; + overlays?: any; +} + +interface EditActionDropdownProps { + item: VisualizationItem; + editItem?(item: VisualizationItem): void; + visbuilderEditItem?(item: VisualizationItem): void; +} + +export const EditActionDropdown: React.FC = ({ + item, + editItem, + visbuilderEditItem, +}) => { + const { overlays } = useOpenSearchDashboards(); + const [isPopoverOpen, setPopoverOpen] = useState(false); + const onButtonClick = () => { + setPopoverOpen(!isPopoverOpen); + }; + + const closePopover = () => { + setPopoverOpen(false); + }; + // A saved object will only have the 'Import to VisBuilder' option + // if it is a VisBuilder-compatible type and its version is <= 1. + const typeName = item.typeTitle; + const itemVersion = item.version; + const isVisBuilderCompatible = + types.includes(typeName) && itemVersion !== undefined && itemVersion <= 1; + + const handleImportToVisBuilder = () => { + closePopover(); // Close the popover first + + const modal = overlays.openModal( + modal.close()} + onConfirm={async () => { + modal.close(); + // Call visbuilderEditItem with the item + if (visbuilderEditItem) { + await visbuilderEditItem(item); + } + }} + cancelButtonText="Cancel" + confirmButtonText="Import" + > + +

+ {' '} + Note that not all settings have been migrated from the original visualization. More will + be included as VisBuilder supports additional settings.{' '} +

+
+
+ ); + }; + + const items = [ + } + onClick={() => { + closePopover(); + editItem?.(item); + }} + data-test-subj="dashboardEditDashboard" + > + {i18n.translate('editActionDropdown.edit', { defaultMessage: 'Edit' })} + , + ]; + if (isVisBuilderCompatible) { + items.push( + } + onClick={handleImportToVisBuilder} + data-test-subj="dashboardImportToVisBuilder" + > + {i18n.translate('editActionDropdown.importToVisBuilder', { + defaultMessage: 'Import to VisBuilder', + })} + + ); + } + + return ( + } + isOpen={isPopoverOpen} + closePopover={closePopover} + panelPaddingSize="none" + anchorPosition="downLeft" + initialFocus="none" + > + + + ); +}; diff --git a/src/plugins/opensearch_dashboards_react/public/table_list_view/table_list_view.tsx b/src/plugins/opensearch_dashboards_react/public/table_list_view/table_list_view.tsx index 8da90e3428e5..04f17a253ab4 100644 --- a/src/plugins/opensearch_dashboards_react/public/table_list_view/table_list_view.tsx +++ b/src/plugins/opensearch_dashboards_react/public/table_list_view/table_list_view.tsx @@ -50,6 +50,7 @@ import { } from '@elastic/eui'; import { HttpFetchError, ToastsStart } from 'opensearch-dashboards/public'; import { toMountPoint } from '../util'; +import { EditActionDropdown, VisualizationItem } from './edit_action_dropdown'; interface Column { name: string; @@ -57,18 +58,15 @@ interface Column { actions?: object[]; } -interface Item { - id?: string; -} - export interface TableListViewProps { createButton?: JSX.Element; createItem?(): void; deleteItems?(items: object[]): Promise; editItem?(item: object): void; + visbuilderEditItem?(item: object): void; entityName: string; entityNamePlural: string; - findItems(query: string): Promise<{ total: number; hits: object[] }>; + findItems(query: string): Promise<{ total: number; hits: VisualizationItem[] }>; listingLimit: number; initialFilter: string; initialPageSize: number; @@ -88,7 +86,7 @@ export interface TableListViewProps { } export interface TableListViewState { - items: object[]; + items: VisualizationItem[]; hasInitialFetchReturned: boolean; isFetchingItems: boolean; isDeletingItems: boolean; @@ -119,7 +117,7 @@ class TableListView extends React.Component { + onSelectionChange: (obj: VisualizationItem[]) => { this.setState({ selectedIds: obj .map((item) => item.id) @@ -444,10 +442,16 @@ class TableListView extends React.Component !error, - onClick: this.props.editItem, + 'data-test-subj': 'edit-dashboard-action', + render: (item: VisualizationItem) => ( + + ), }, ]; - const search = { onChange: this.setFilter.bind(this), toolsLeft: this.renderToolsLeft(), @@ -458,7 +462,7 @@ class TableListView extends React.Component ); return ( - itemId="id" items={this.state.items} - columns={(columns as unknown) as Array>} // EuiBasicTableColumn is stricter than Column + columns={(columns as unknown) as Array>} // EuiBasicTableColumn is stricter than Column pagination={this.pagination} loading={this.state.isFetchingItems} message={noItemsMessage} diff --git a/src/plugins/vis_builder/public/application/components/data_tab/secondary_panel.tsx b/src/plugins/vis_builder/public/application/components/data_tab/secondary_panel.tsx index 18a1991f6d80..4857647420e5 100644 --- a/src/plugins/vis_builder/public/application/components/data_tab/secondary_panel.tsx +++ b/src/plugins/vis_builder/public/application/components/data_tab/secondary_panel.tsx @@ -28,7 +28,7 @@ export function SecondaryPanel() { const { draftAgg, aggConfigParams } = useTypedSelector( (state) => state.visualization.activeVisualization! ); - const isEditorValid = useTypedSelector((state) => !state.metadata.editor.errors[PANEL_KEY]); + const isEditorValid = useTypedSelector((state) => !state.metadata.editor.errors?.[PANEL_KEY]); const [touched, setTouched] = useState(false); const dispatch = useTypedDispatch(); const vizType = useVisualizationType(); diff --git a/src/plugins/vis_builder/public/application/utils/breadcrumbs.ts b/src/plugins/vis_builder/public/application/utils/breadcrumbs.ts index 1f5d15a93382..eeafa40fe015 100644 --- a/src/plugins/vis_builder/public/application/utils/breadcrumbs.ts +++ b/src/plugins/vis_builder/public/application/utils/breadcrumbs.ts @@ -21,13 +21,17 @@ export function getVisualizeLandingBreadcrumbs(navigateToApp) { ]; } -export function getCreateBreadcrumbs(navigateToApp) { +export function getCreateBreadcrumbs(navigateToApp, isMigrated: boolean) { return [ ...getVisualizeLandingBreadcrumbs(navigateToApp), { - text: i18n.translate('visBuilder.editor.createBreadcrumb', { - defaultMessage: 'Create', - }), + text: isMigrated + ? i18n.translate('visBuilder.editor.newVisualizationBreadcrumb', { + defaultMessage: 'New visualization', + }) + : i18n.translate('visBuilder.editor.createBreadcrumb', { + defaultMessage: 'Create', + }), }, ]; } diff --git a/src/plugins/vis_builder/public/application/utils/get_top_nav_config.tsx b/src/plugins/vis_builder/public/application/utils/get_top_nav_config.tsx index 42f3e68c3898..6dccaa283bed 100644 --- a/src/plugins/vis_builder/public/application/utils/get_top_nav_config.tsx +++ b/src/plugins/vis_builder/public/application/utils/get_top_nav_config.tsx @@ -38,9 +38,9 @@ import { } from '../../../../saved_objects/public'; import { VisBuilderServices } from '../..'; import { VisBuilderSavedObject } from '../../types'; -import { AppDispatch } from './state_management'; +import { AppDispatch, setMetadataState } from './state_management'; import { EDIT_PATH, VISBUILDER_SAVED_OBJECT } from '../../../common'; -import { setEditorState } from './state_management/metadata_slice'; + export interface TopNavConfigParams { visualizationIdFromUrl: string; savedVisBuilderVis: VisBuilderSavedObject; @@ -243,7 +243,14 @@ export const getOnSave = ( pathname: `${EDIT_PATH}/${id}`, }); } - dispatch(setEditorState({ state: 'clean' })); + dispatch( + setMetadataState({ + editor: { + state: 'clean', + }, + isMigrated: false, + }) + ); } else { // reset title if save not successful savedVisBuilderVis.title = currentTitle; diff --git a/src/plugins/vis_builder/public/application/utils/state_management/metadata_slice.ts b/src/plugins/vis_builder/public/application/utils/state_management/metadata_slice.ts index 880c15f3e44a..bc46a603ffa8 100644 --- a/src/plugins/vis_builder/public/application/utils/state_management/metadata_slice.ts +++ b/src/plugins/vis_builder/public/application/utils/state_management/metadata_slice.ts @@ -15,13 +15,14 @@ type EditorState = 'loading' | 'loaded' | 'clean' | 'dirty'; export interface MetadataState { editor: { - errors: { + errors?: { // Errors for each section in the editor [key: string]: boolean; }; state: EditorState; }; originatingApp?: string; + isMigrated?: boolean; } const initialState: MetadataState = { @@ -30,6 +31,7 @@ const initialState: MetadataState = { state: 'loading', }, originatingApp: undefined, + isMigrated: false, }; export const getPreloadedState = async ({ @@ -53,7 +55,7 @@ export const slice = createSlice({ reducers: { setError: (state, action: PayloadAction<{ key: string; error: boolean }>) => { const { key, error } = action.payload; - state.editor.errors[key] = error; + (state.editor.errors ??= {})[key] = error; }, setEditorState: (state, action: PayloadAction<{ state: EditorState }>) => { state.editor.state = action.payload.state; diff --git a/src/plugins/vis_builder/public/application/utils/state_management/redux_persistence.test.tsx b/src/plugins/vis_builder/public/application/utils/state_management/redux_persistence.test.tsx index a46d5c027656..9c4965541d0e 100644 --- a/src/plugins/vis_builder/public/application/utils/state_management/redux_persistence.test.tsx +++ b/src/plugins/vis_builder/public/application/utils/state_management/redux_persistence.test.tsx @@ -33,6 +33,7 @@ describe('test redux state persistence', () => { metadata: { editor: { errors: {}, state: 'loading' }, originatingApp: undefined, + isMigrated: false, }, ui: {}, }; diff --git a/src/plugins/vis_builder/public/application/utils/state_management/store.ts b/src/plugins/vis_builder/public/application/utils/state_management/store.ts index 8fe5c23fd657..b55e6ce988e2 100644 --- a/src/plugins/vis_builder/public/application/utils/state_management/store.ts +++ b/src/plugins/vis_builder/public/application/utils/state_management/store.ts @@ -62,5 +62,5 @@ export type AppDispatch = Store['dispatch']; export { setState as setStyleState, StyleState } from './style_slice'; export { setState as setVisualizationState, VisualizationState } from './visualization_slice'; -export { MetadataState } from './metadata_slice'; +export { setState as setMetadataState, MetadataState } from './metadata_slice'; export { setState as setUIStateState, UIStateState } from './ui_state_slice'; diff --git a/src/plugins/vis_builder/public/application/utils/use/use_can_save.ts b/src/plugins/vis_builder/public/application/utils/use/use_can_save.ts index 7da320d266f3..46125bc82ba9 100644 --- a/src/plugins/vis_builder/public/application/utils/use/use_can_save.ts +++ b/src/plugins/vis_builder/public/application/utils/use/use_can_save.ts @@ -10,7 +10,9 @@ export const useCanSave = () => { const isEmpty = useTypedSelector( (state) => state.visualization.activeVisualization?.aggConfigParams?.length === 0 ); - const hasNoChange = useTypedSelector((state) => state.metadata.editor.state !== 'dirty'); + const hasNoChange = useTypedSelector((state) => { + return state.metadata.editor.state !== 'dirty' && state.metadata.isMigrated === false; + }); const hasDraftAgg = useTypedSelector( (state) => !!state.visualization.activeVisualization?.draftAgg ); 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 8f67b8d2358f..1dd963495c71 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 @@ -5,6 +5,7 @@ import { i18n } from '@osd/i18n'; import { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; import { SavedObject } from '../../../../../saved_objects/public'; import { InvalidJSONProperty, @@ -30,6 +31,7 @@ export const useSavedVisBuilderVis = (visualizationIdFromUrl: string | undefined const { services } = useOpenSearchDashboards(); const [savedVisState, setSavedVisState] = useState(undefined); const dispatch = useTypedDispatch(); + const isMigrated = useSelector((state: any) => state.metadata?.isMigrated); useEffect(() => { const { @@ -60,8 +62,17 @@ export const useSavedVisBuilderVis = (visualizationIdFromUrl: string | undefined if (savedVisBuilderVis.id) { const { title, state } = getStateFromSavedObject(savedVisBuilderVis); - chrome.setBreadcrumbs(getEditBreadcrumbs(title, navigateToApp)); - chrome.docTitle.change(title); + + // Use isMigrated to determine which breadcrumb function to use + const breadcrumbs = isMigrated + ? getCreateBreadcrumbs(navigateToApp, isMigrated) + : getEditBreadcrumbs(title, navigateToApp); + + chrome.setBreadcrumbs(breadcrumbs); + + // Change the title based on isMigrated + const newTitle = isMigrated ? 'New Visualization' : title; + chrome.docTitle.change(newTitle); // sync initial app filters from savedObject to filterManager const filters = savedVisBuilderVis.searchSourceFields.filter; const query = @@ -86,7 +97,7 @@ export const useSavedVisBuilderVis = (visualizationIdFromUrl: string | undefined dispatch(setVisualizationState(state.visualization)); dispatch(setEditorState({ state: 'loaded' })); } else { - chrome.setBreadcrumbs(getCreateBreadcrumbs(navigateToApp)); + chrome.setBreadcrumbs(getCreateBreadcrumbs(navigateToApp, isMigrated)); } setSavedVisState(savedVisBuilderVis); @@ -121,7 +132,7 @@ export const useSavedVisBuilderVis = (visualizationIdFromUrl: string | undefined }; loadSavedVisBuilderVis(); - }, [dispatch, services, visualizationIdFromUrl]); + }, [dispatch, services, visualizationIdFromUrl, isMigrated]); return savedVisState; }; diff --git a/src/plugins/visualize/public/application/components/visualize_listing.tsx b/src/plugins/visualize/public/application/components/visualize_listing.tsx index ead43a7b08ca..c1b7c211bba0 100644 --- a/src/plugins/visualize/public/application/components/visualize_listing.tsx +++ b/src/plugins/visualize/public/application/components/visualize_listing.tsx @@ -45,6 +45,7 @@ import { getTableColumns, getNoItemsMessage } from '../utils'; import { getUiActions } from '../../services'; import { SAVED_OBJECT_DELETE_TRIGGER } from '../../../../saved_objects_management/public'; import { HeaderVariant } from '../../../../../core/public/index'; +import { constructVisBuilderPath } from '../utils/construct_vis_builder_path'; export const VisualizeListing = () => { const { @@ -125,6 +126,18 @@ export const VisualizeListing = () => { [application, history] ); + const { services: visualizeServices } = useOpenSearchDashboards(); + + // This function takes a legacy visualization item as input and constructs the appropriate path. + // It then navigates to the VisBuilder app with the constructed path to migrate the legacy visualization. + const visbuilderEditItem = useCallback( + async (item) => { + const path = await constructVisBuilderPath(item, visualizeServices); + application.navigateToApp('vis-builder', { path }); + }, + [visualizeServices, application] + ); + const noItemsFragment = useMemo(() => getNoItemsMessage(createNewVis), [createNewVis]); const tableColumns = useMemo(() => getTableColumns(application, history, uiSettings), [ application, @@ -204,6 +217,7 @@ export const VisualizeListing = () => { findItems={fetchItems} deleteItems={visualizeCapabilities.delete ? deleteItems : undefined} editItem={visualizeCapabilities.save ? editItem : undefined} + visbuilderEditItem={visbuilderEditItem} tableColumns={tableColumns} listingLimit={listingLimit} initialPageSize={savedObjectsPublic.settings.getPerPage()} diff --git a/src/plugins/visualize/public/application/utils/construct_vis_builder_path.ts b/src/plugins/visualize/public/application/utils/construct_vis_builder_path.ts new file mode 100644 index 000000000000..4f132b86f664 --- /dev/null +++ b/src/plugins/visualize/public/application/utils/construct_vis_builder_path.ts @@ -0,0 +1,65 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { getVisualizationInstance } from './get_visualization_instance'; +import { setStateToOsdUrl } from '../../../../opensearch_dashboards_utils/public'; +import { VisualizeServices } from '../types'; + +export const constructVisBuilderPath = async ( + item: { id: string | Record | undefined }, + visualizeServices: VisualizeServices +) => { + const { savedVis } = await getVisualizationInstance(visualizeServices, item.id); + + const indexPattern = savedVis.searchSourceFields?.index; + const name = savedVis.visState.type; + const legend = savedVis.visState.params.addLegend; + const tooltip = savedVis.visState.params.addTooltip; + const config = savedVis.visState.aggs; + const position = savedVis.visState.params.legendPosition; + const type = savedVis.visState.type; + const uiState = savedVis.uiStateJSON; + const filter = savedVis.searchSourceFields?.filter; + const query = savedVis.searchSourceFields?.query; + const metric = savedVis.visState.params.metric; + + const _q = { + filters: filter, + query, + }; + + const _a = { + metadata: { + editor: { + errors: {}, + state: 'clean', + }, + isMigrated: true, + }, + style: { + addLegend: legend, + addTooltip: tooltip, + legendPosition: position, + type, + metric, + }, + ui: { uiState }, + visualization: { + activeVisualization: { + aggConfigParams: config, + name, + }, + indexPattern, + searchField: '', + }, + }; + + // Construct the path for VisBuilder and set the states to URL + let visBuilderPath = '/app/vis-builder#/'; + visBuilderPath = setStateToOsdUrl('_q', _q, { useHash: false }, visBuilderPath); + visBuilderPath = setStateToOsdUrl('_a', _a, { useHash: false }, visBuilderPath); + + return visBuilderPath; +}; diff --git a/src/plugins/visualize/public/application/utils/contruct_vis_builder_path.test.ts b/src/plugins/visualize/public/application/utils/contruct_vis_builder_path.test.ts new file mode 100644 index 000000000000..4090fefa2f48 --- /dev/null +++ b/src/plugins/visualize/public/application/utils/contruct_vis_builder_path.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// Mock the entire module +jest.mock('./construct_vis_builder_path'); + +// Import the mocked module +import { constructVisBuilderPath } from './construct_vis_builder_path'; + +describe('constructVisBuilderPath', () => { + const mockVisualizeServices = {} as any; + const mockItem = { id: 'test-id' }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return a URL with _q and _a parameters', async () => { + const mockUrl = '/app/vis-builder#/_q={"filters":[],"query":""}&_a={"param":"value"}'; + (constructVisBuilderPath as jest.Mock).mockResolvedValue(mockUrl); + + const result = await constructVisBuilderPath(mockItem, mockVisualizeServices); + + expect(result).toContain('/app/vis-builder#/'); + expect(result).toContain('_q='); + expect(result).toContain('_a='); + }); + + it('should include filters and query in _q parameter', async () => { + const mockUrl = '/app/vis-builder#/_q={"filters":["test"],"query":"test query"}&_a={}'; + (constructVisBuilderPath as jest.Mock).mockResolvedValue(mockUrl); + + const result = await constructVisBuilderPath(mockItem, mockVisualizeServices); + + expect(result).toContain('"filters":["test"]'); + expect(result).toContain('"query":"test query"'); + }); + + it('should handle empty _q parameter', async () => { + const mockUrl = '/app/vis-builder#/_q={}&_a={}'; + (constructVisBuilderPath as jest.Mock).mockResolvedValue(mockUrl); + + const result = await constructVisBuilderPath(mockItem, mockVisualizeServices); + + expect(result).toContain('_q={}'); + }); + + it('should include _a parameter with some content', async () => { + const mockUrl = '/app/vis-builder#/_q={}&_a={"someKey":"someValue"}'; + (constructVisBuilderPath as jest.Mock).mockResolvedValue(mockUrl); + + const result = await constructVisBuilderPath(mockItem, mockVisualizeServices); + + expect(result).toContain('_a={"someKey":"someValue"}'); + }); +}); diff --git a/test/plugin_functional/test_suites/dashboard_listing_plugin/dashboard_listing_plugin.ts b/test/plugin_functional/test_suites/dashboard_listing_plugin/dashboard_listing_plugin.ts index 94bfb192e356..3ffa225779d1 100644 --- a/test/plugin_functional/test_suites/dashboard_listing_plugin/dashboard_listing_plugin.ts +++ b/test/plugin_functional/test_suites/dashboard_listing_plugin/dashboard_listing_plugin.ts @@ -54,8 +54,13 @@ export default function ({ getService, getPageObjects }) { it('should be able to navigate to edit dashboard', async () => { await listingTable.searchForItemWithName(dashboardName); - const editBttn = await find.allByCssSelector('.euiToolTipAnchor'); - await editBttn[2].click(); + // Find and click the edit button + const editBtn = await testSubjects.find('dashboardEditBtn'); + await editBtn.click(); + + // Find and click the edit option in the dropdown + const editOption = await testSubjects.find('dashboardEditDashboard'); + await editOption.click(); await PageObjects.dashboard.clickCancelOutOfEditMode(); await PageObjects.dashboard.gotoDashboardLandingPage(); }); From a11bb7da394352aa4d9a5fac5c1e15c966bc63d4 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:59:16 -0700 Subject: [PATCH 271/276] Fix Run button position when datepicker is not visible (#7935) (#7946) (cherry picked from commit e5c125d8ced10af0c9fbfa274f12fe935e69bda8) Signed-off-by: Suchit Sahoo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../public/top_nav_menu/top_nav_menu.tsx | 31 ++++++------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index 49db1401c7ea..076984c0060a 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -202,31 +202,20 @@ export function TopNavMenu(props: TopNavMenuProps): ReactElement | null { // Show the SearchBar in-place default: - if (showDatePicker === TopNavMenuItemRenderType.IN_PORTAL) { - return ( - <> - - - - {screenTitle} - - {renderMenu(menuClassName)} - -
- - - - {renderSearchBar({ datePickerRef })} - - ); - } - return ( <> - {renderMenu(menuClassName)} + + + {screenTitle} + + {renderMenu(menuClassName)} + +
+ + - {renderSearchBar()} + {renderSearchBar({ datePickerRef })} ); } From 5778bd2953e6f4780cbedd9352cdd69585617593 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 16:30:31 -0700 Subject: [PATCH 272/276] [Auto Suggest] PPL autocomplete and interface changes (#7932) (#7950) * [Autocomplete - SQL] Minor interface change to add suggestion type and move suggestion provider registration location (#7758) * add table/source as prefix to suggested fields * add type to column * move registeration to osd/monaco * add detail * Changeset file for PR #7758 created/updated --------- * [Autocomplete] PPL Autocomplete (#7810) * add initial ppl autocomplete * untrack .antlr files * ignore intermediate grammar auto-gen files * add rules and related functionalities * Changeset file for PR #7810 created/updated * Changeset file for PR #7810 created/updated * minor comment cleanning * add ppl generation command * add rules * correct typo * fix inserting text issue * remove colon for PPL field --------- * small interface updates * small type update * make inclusion for pipe, comma, and equal tokens * refactor and generalize field fetcher for dql and ppl, including details * use field fetching util for sql and update sugg detail for dql * detail for ppl * create range parameter to help identify suggestions with whitespace, implemented dql value WS suggs * single line editor overflow initial override for sugg window * update dql tests to account for details and value ranges --------- (cherry picked from commit 0245540301ece09642557aa495982720f78a80a0) Signed-off-by: Eric Signed-off-by: Paul Sebastian Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: Eric Wei Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- .gitignore | 3 +- changelogs/fragments/7758.yml | 2 + changelogs/fragments/7810.yml | 2 + package.json | 3 +- .../osd-monaco/src/xjson/lexer_rules/index.ts | 4 + .../src/xjson/lexer_rules/opensearchppl.ts | 529 + .../src/xjson/lexer_rules/opensearchsql.ts | 4 + .../public/antlr/dql/code_completion.test.ts | 137 +- .../data/public/antlr/dql/code_completion.ts | 37 +- .../.generated/OpenSearchPPLLexer.interp | 1033 ++ .../.generated/OpenSearchPPLLexer.tokens | 659 + .../.generated/OpenSearchPPLLexer.ts | 1880 +++ .../.generated/OpenSearchPPLParser.interp | 797 + .../.generated/OpenSearchPPLParser.tokens | 659 + .../.generated/OpenSearchPPLParser.ts | 12797 ++++++++++++++++ .../.generated/OpenSearchPPLParserVisitor.ts | 975 ++ .../antlr/opensearch_ppl/code_completion.ts | 72 + .../grammar/OpenSearchPPLLexer.g4 | 406 + .../grammar/OpenSearchPPLParser.g4 | 914 ++ .../opensearch_ppl_autocomplete.ts | 146 + .../antlr/opensearch_sql/code_completion.ts | 139 +- .../data/public/antlr/shared/constants.ts | 12 + .../antlr/shared/general_error_listerner.ts | 47 + src/plugins/data/public/antlr/shared/types.ts | 23 + src/plugins/data/public/antlr/shared/utils.ts | 89 + .../providers/query_suggestion_provider.ts | 17 +- src/plugins/data/public/plugin.ts | 8 +- .../public/ui/query_editor/_query_editor.scss | 1 + .../public/ui/query_editor/query_editor.tsx | 36 +- 29 files changed, 21208 insertions(+), 223 deletions(-) create mode 100644 changelogs/fragments/7758.yml create mode 100644 changelogs/fragments/7810.yml create mode 100644 packages/osd-monaco/src/xjson/lexer_rules/opensearchppl.ts create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.interp create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.tokens create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.ts create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.interp create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.tokens create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.ts create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParserVisitor.ts create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/code_completion.ts create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLLexer.g4 create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLParser.g4 create mode 100644 src/plugins/data/public/antlr/opensearch_ppl/opensearch_ppl_autocomplete.ts create mode 100644 src/plugins/data/public/antlr/shared/constants.ts create mode 100644 src/plugins/data/public/antlr/shared/general_error_listerner.ts diff --git a/.gitignore b/.gitignore index c530adedb7bb..f62e798ad6a5 100644 --- a/.gitignore +++ b/.gitignore @@ -70,5 +70,4 @@ snapshots.js .yarn-local-mirror # Ignore the generated antlr files -/src/plugins/data/public/antlr/opensearch_sql/grammar/.antlr -/src/plugins/data/public/antlr/dql/grammar/.antlr \ No newline at end of file +/src/plugins/data/public/antlr/**/grammar/.antlr/ \ No newline at end of file diff --git a/changelogs/fragments/7758.yml b/changelogs/fragments/7758.yml new file mode 100644 index 000000000000..ecc1f7b1defa --- /dev/null +++ b/changelogs/fragments/7758.yml @@ -0,0 +1,2 @@ +feat: +- Minor interface change and move suggestion provider registration location ([#7758](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7758)) \ No newline at end of file diff --git a/changelogs/fragments/7810.yml b/changelogs/fragments/7810.yml new file mode 100644 index 000000000000..104d2d23e27c --- /dev/null +++ b/changelogs/fragments/7810.yml @@ -0,0 +1,2 @@ +feat: +- Add OpenSearch PPL autocomplete to discover 2.0 with query enhancements ([#7810](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7810)) \ No newline at end of file diff --git a/package.json b/package.json index 952a5aa08af9..56bef8bb1c94 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,8 @@ "cypress:run-with-security": "env TZ=America/Los_Angeles NO_COLOR=1 cypress run --headless --env SECURITY_ENABLED=true,openSearchUrl=https://localhost:9200,WAIT_FOR_LOADER_BUFFER_MS=500", "osd:ciGroup10": "echo \"dashboard_sanity_test_spec.js\"", "osd:ciGroup11": "echo \"apps/vis_builder/*.js\"", - "generate:opensearchsqlantlr": "./node_modules/antlr4ng-cli/index.js -Dlanguage=TypeScript -o ./src/plugins/data/public/antlr/opensearch_sql/.generated -visitor -no-listener -Xexact-output-dir ./src/plugins/data/public/antlr/opensearch_sql/grammar/OpenSearchSQLLexer.g4 ./src/plugins/data/public/antlr/opensearch_sql/grammar/OpenSearchSQLParser.g4" + "generate:opensearchsqlantlr": "./node_modules/antlr4ng-cli/index.js -Dlanguage=TypeScript -o ./src/plugins/data/public/antlr/opensearch_sql/.generated -visitor -no-listener -Xexact-output-dir ./src/plugins/data/public/antlr/opensearch_sql/grammar/OpenSearchSQLLexer.g4 ./src/plugins/data/public/antlr/opensearch_sql/grammar/OpenSearchSQLParser.g4", + "generate:opensearchpplantlr": "./node_modules/antlr4ng-cli/index.js -Dlanguage=TypeScript -o ./src/plugins/data/public/antlr/opensearch_ppl/.generated -visitor -no-listener -Xexact-output-dir ./src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLLexer.g4 ./src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLParser.g4" }, "repository": { "type": "git", diff --git a/packages/osd-monaco/src/xjson/lexer_rules/index.ts b/packages/osd-monaco/src/xjson/lexer_rules/index.ts index 496769020e55..1e836eb4fed7 100644 --- a/packages/osd-monaco/src/xjson/lexer_rules/index.ts +++ b/packages/osd-monaco/src/xjson/lexer_rules/index.ts @@ -34,6 +34,7 @@ import * as xJson from './xjson'; import * as opensearchql from './opensearchql'; import * as painless from './painless'; import * as opensearchsql from './opensearchsql'; +import * as opensearchppl from './opensearchppl'; export const registerLexerRules = (m: typeof monaco) => { m.languages.register({ id: xJson.ID }); @@ -44,4 +45,7 @@ export const registerLexerRules = (m: typeof monaco) => { m.languages.setMonarchTokensProvider(opensearchql.ID, opensearchql.lexerRules); m.languages.register({ id: opensearchsql.ID }); m.languages.setMonarchTokensProvider(opensearchsql.ID, opensearchsql.lexerRules); + m.languages.register({ id: opensearchppl.ID }); + m.languages.setMonarchTokensProvider(opensearchppl.ID, opensearchppl.lexerRules); + m.languages.register({ id: 'kuery' }); }; diff --git a/packages/osd-monaco/src/xjson/lexer_rules/opensearchppl.ts b/packages/osd-monaco/src/xjson/lexer_rules/opensearchppl.ts new file mode 100644 index 000000000000..f303c8fa9e77 --- /dev/null +++ b/packages/osd-monaco/src/xjson/lexer_rules/opensearchppl.ts @@ -0,0 +1,529 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { monaco } from '../../monaco'; + +export const ID = 'PPL'; + +const brackets = [ + { open: '[', close: ']', token: 'delimiter.square' }, + { open: '(', close: ')', token: 'delimiter.parenthesis' }, +]; + +const keywords = [ + // COMMAND KEYWORDS + 'SEARCH', + 'DESCRIBE', + 'SHOW', + 'FROM', + 'WHERE', + 'FIELDS', + 'RENAME', + 'STATS', + 'DEDUP', + 'SORT', + 'EVAL', + 'HEAD', + 'TOP', + 'RARE', + 'PARSE', + 'METHOD', + 'REGEX', + 'PUNCT', + 'GROK', + 'PATTERN', + 'PATTERNS', + 'NEW_FIELD', + 'KMEANS', + 'AD', + 'ML', + + // COMMAND ASSIST KEYWORDS + 'AS', + 'BY', + 'SOURCE', + 'INDEX', + 'D', + 'DESC', + 'DATASOURCES', + + // CLAUSE KEYWORDS + 'SORTBY', + + // FIELD KEYWORDS + 'AUTO', + 'STR', + 'IP', + 'NUM', + + // ARGUMENT KEYWORDS + 'KEEPEMPTY', + 'CONSECUTIVE', + 'DEDUP_SPLITVALUES', + 'PARTITIONS', + 'ALLNUM', + 'DELIM', + 'CENTROIDS', + 'ITERATIONS', + 'DISTANCE_TYPE', + 'NUMBER_OF_TREES', + 'SHINGLE_SIZE', + 'SAMPLE_SIZE', + 'OUTPUT_AFTER', + 'TIME_DECAY', + 'ANOMALY_RATE', + 'CATEGORY_FIELD', + 'TIME_FIELD', + 'TIME_ZONE', + 'TRAINING_DATA_SIZE', + 'ANOMALY_SCORE_THRESHOLD', + + // COMPARISON FUNCTION KEYWORDS + 'CASE', + 'IN', + + // LOGICAL KEYWORDS + 'NOT', + 'OR', + 'AND', + 'XOR', + 'TRUE', + 'FALSE', + 'REGEXP', + + // DATETIME, INTERVAL AND UNIT KEYWORDS + 'CONVERT_TZ', + 'DATETIME', + 'DAY', + 'DAY_HOUR', + 'DAY_MICROSECOND', + 'DAY_MINUTE', + 'DAY_OF_YEAR', + 'DAY_SECOND', + 'HOUR', + 'HOUR_MICROSECOND', + 'HOUR_MINUTE', + 'HOUR_OF_DAY', + 'HOUR_SECOND', + 'INTERVAL', + 'MICROSECOND', + 'MILLISECOND', + 'MINUTE', + 'MINUTE_MICROSECOND', + 'MINUTE_OF_DAY', + 'MINUTE_OF_HOUR', + 'MINUTE_SECOND', + 'MONTH', + 'MONTH_OF_YEAR', + 'QUARTER', + 'SECOND', + 'SECOND_MICROSECOND', + 'SECOND_OF_MINUTE', + 'WEEK', + 'WEEK_OF_YEAR', + 'YEAR', + 'YEAR_MONTH', + + // DATASET TYPES + 'DATAMODEL', + 'LOOKUP', + 'SAVEDSEARCH', + + // CONVERTED DATA TYPES + 'INT', + 'INTEGER', + 'DOUBLE', + 'LONG', + 'FLOAT', + 'STRING', + 'BOOLEAN', + + // SPECIAL CHARACTERS AND OPERATORS + 'PIPE', + 'COMMA', + 'DOT', + 'EQUAL', + 'GREATER', + 'LESS', + 'NOT_GREATER', + 'NOT_LESS', + 'NOT_EQUAL', + 'PLUS', + 'MINUS', + 'STAR', + 'DIVIDE', + 'MODULE', + 'EXCLAMATION_SYMBOL', + 'COLON', + 'LT_PRTHS', + 'RT_PRTHS', + 'LT_SQR_PRTHS', + 'RT_SQR_PRTHS', + 'SINGLE_QUOTE', + 'DOUBLE_QUOTE', + 'BACKTICK', + + // AGGREGATIONS + 'AVG', + 'COUNT', + 'DISTINCT_COUNT', + 'ESTDC', + 'ESTDC_ERROR', + 'MAX', + 'MEAN', + 'MEDIAN', + 'MIN', + 'MODE', + 'RANGE', + 'STDEV', + 'STDEVP', + 'SUM', + 'SUMSQ', + 'VAR_SAMP', + 'VAR_POP', + 'STDDEV_SAMP', + 'STDDEV_POP', + 'PERCENTILE', + 'TAKE', + 'FIRST', + 'LAST', + 'LIST', + 'VALUES', + 'EARLIEST', + 'EARLIEST_TIME', + 'LATEST', + 'LATEST_TIME', + 'PER_DAY', + 'PER_HOUR', + 'PER_MINUTE', + 'PER_SECOND', + 'RATE', + 'SPARKLINE', + 'C', + 'DC', + + // BASIC FUNCTIONS + 'ABS', + 'CBRT', + 'CEIL', + 'CEILING', + 'CONV', + 'CRC32', + 'E', + 'EXP', + 'FLOOR', + 'LN', + 'LOG', + 'LOG10', + 'LOG2', + 'MOD', + 'PI', + 'POSITION', + 'POW', + 'POWER', + 'RAND', + 'ROUND', + 'SIGN', + 'SQRT', + 'TRUNCATE', + + // TRIGONOMETRIC FUNCTIONS + 'ACOS', + 'ASIN', + 'ATAN', + 'ATAN2', + 'COS', + 'COT', + 'DEGREES', + 'RADIANS', + 'SIN', + 'TAN', + + // DATE AND TIME FUNCTIONS + 'ADDDATE', + 'ADDTIME', + 'CURDATE', + 'CURRENT_DATE', + 'CURRENT_TIME', + 'CURRENT_TIMESTAMP', + 'CURTIME', + 'DATE', + 'DATEDIFF', + 'DATE_ADD', + 'DATE_FORMAT', + 'DATE_SUB', + 'DAYNAME', + 'DAYOFMONTH', + 'DAYOFWEEK', + 'DAYOFYEAR', + 'DAY_OF_MONTH', + 'DAY_OF_WEEK', + 'DAY_OF_YEAR', + 'EXTRACT', + 'FROM_DAYS', + 'FROM_UNIXTIME', + 'GET_FORMAT', + 'LAST_DAY', + 'LOCALTIME', + 'LOCALTIMESTAMP', + 'MAKEDATE', + 'MAKETIME', + 'MONTHNAME', + 'NOW', + 'PERIOD_ADD', + 'PERIOD_DIFF', + 'SEC_TO_TIME', + 'STR_TO_DATE', + 'SUBDATE', + 'SUBTIME', + 'SYSDATE', + 'TIME', + 'TIMEDIFF', + 'TIMESTAMP', + 'TIMESTAMPADD', + 'TIMESTAMPDIFF', + 'TIME_FORMAT', + 'TIME_TO_SEC', + 'TO_DAYS', + 'TO_SECONDS', + 'UNIX_TIMESTAMP', + 'UTC_DATE', + 'UTC_TIME', + 'UTC_TIMESTAMP', + 'WEEKDAY', + 'YEARWEEK', + + // TEXT FUNCTIONS + 'SUBSTR', + 'SUBSTRING', + 'LTRIM', + 'RTRIM', + 'TRIM', + 'TO', + 'LOWER', + 'UPPER', + 'CONCAT', + 'CONCAT_WS', + 'LENGTH', + 'STRCMP', + 'RIGHT', + 'LEFT', + 'ASCII', + 'LOCATE', + 'REPLACE', + 'REVERSE', + 'CAST', + + // BOOL FUNCTIONS + 'LIKE', + 'ISNULL', + 'ISNOTNULL', + + // FLOWCONTROL FUNCTIONS + 'IFNULL', + 'NULLIF', + 'IF', + 'TYPEOF', + + // RELEVANCE FUNCTIONS AND PARAMETERS + 'MATCH', + 'MATCH_PHRASE', + 'MATCH_PHRASE_PREFIX', + 'MATCH_BOOL_PREFIX', + 'SIMPLE_QUERY_STRING', + 'MULTI_MATCH', + 'QUERY_STRING', + 'ALLOW_LEADING_WILDCARD', + 'ANALYZE_WILDCARD', + 'ANALYZER', + 'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY', + 'BOOST', + 'CUTOFF_FREQUENCY', + 'DEFAULT_FIELD', + 'DEFAULT_OPERATOR', + 'ENABLE_POSITION_INCREMENTS', + 'ESCAPE', + 'FLAGS', + 'FUZZY_MAX_EXPANSIONS', + 'FUZZY_PREFIX_LENGTH', + 'FUZZY_TRANSPOSITIONS', + 'FUZZY_REWRITE', + 'FUZZINESS', + 'LENIENT', + 'LOW_FREQ_OPERATOR', + 'MAX_DETERMINIZED_STATES', + 'MAX_EXPANSIONS', + 'MINIMUM_SHOULD_MATCH', + 'OPERATOR', + 'PHRASE_SLOP', + 'PREFIX_LENGTH', + 'QUOTE_ANALYZER', + 'QUOTE_FIELD_SUFFIX', + 'REWRITE', + 'SLOP', + 'TIE_BREAKER', + 'TYPE', + 'ZERO_TERMS_QUERY', + + // SPAN KEYWORDS + 'SPAN', + 'MS', + 'S', + 'M', + 'H', + 'W', + 'Q', + 'Y', +]; + +const builtinFunctions = [ + 'ABS', + 'CBRT', + 'CEIL', + 'CEILING', + 'CONV', + 'CRC32', + 'E', + 'EXP', + 'FLOOR', + 'LN', + 'LOG', + 'LOG10', + 'LOG2', + 'MOD', + 'PI', + 'POSITION', + 'POW', + 'POWER', + 'RAND', + 'ROUND', + 'SIGN', + 'SQRT', + 'TRUNCATE', + 'ACOS', + 'ASIN', + 'ATAN', + 'ATAN2', + 'COS', + 'COT', + 'DEGREES', + 'RADIANS', + 'SIN', + 'TAN', + 'ADDDATE', + 'ADDTIME', + 'CURDATE', + 'CURRENT_DATE', + 'CURRENT_TIME', + 'CURRENT_TIMESTAMP', + 'CURTIME', + 'DATE', + 'DATEDIFF', + 'DATE_ADD', + 'DATE_FORMAT', + 'DATE_SUB', + 'DAYNAME', + 'DAYOFMONTH', + 'DAYOFWEEK', + 'DAYOFYEAR', + 'DAY_OF_MONTH', + 'DAY_OF_WEEK', + 'DAY_OF_YEAR', + 'EXTRACT', + 'FROM_DAYS', + 'FROM_UNIXTIME', + 'GET_FORMAT', + 'LAST_DAY', + 'LOCALTIME', + 'LOCALTIMESTAMP', + 'MAKEDATE', + 'MAKETIME', + 'MONTHNAME', + 'NOW', + 'PERIOD_ADD', + 'PERIOD_DIFF', + 'SEC_TO_TIME', + 'STR_TO_DATE', + 'SUBDATE', + 'SUBTIME', + 'SYSDATE', + 'TIME', + 'TIMEDIFF', + 'TIMESTAMP', + 'TIMESTAMPADD', + 'TIMESTAMPDIFF', + 'TIME_FORMAT', + 'TIME_TO_SEC', + 'TO_DAYS', + 'TO_SECONDS', + 'UNIX_TIMESTAMP', + 'UTC_DATE', + 'UTC_TIME', + 'UTC_TIMESTAMP', + 'WEEKDAY', + 'YEARWEEK', +]; + +export const lexerRules = { + defaultToken: 'invalid', + ignoreCase: true, + tokenPostfix: '', + keywords, + builtinFunctions, + brackets, + tokenizer: { + root: [ + [ + /[a-zA-Z_$][a-zA-Z0-9_$]*\b/, + { + cases: { + '@keywords': 'keyword', + '@builtinFunctions': 'identifier', + '@default': 'identifier', + }, + }, + ], + [/[()]/, '@brackets'], + [/--.*$/, 'comment'], + [/\/\*/, 'comment', '@comment'], + [/\/.*$/, 'comment'], + + [/".*?"/, 'string'], + [/'.*?'/, 'constant'], + [/`.*?`/, 'string'], + + // whitespace + [/[ \t\r\n]+/, { token: '@whitespace' }], + [/[+-]?\d+(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/, 'number'], + [/⇐|<⇒|\*|\.|\:\:|\+|\-|\/|\/\/|%|&|\^|~|<|>|<=|=>|==|!=|<>|=/, 'keyword.operator'], + [/[\(]/, 'paren.lparen'], + [/[\)]/, 'paren.rparen'], + [/\s+/, 'text'], + ], + numbers: [ + [/0[xX][0-9a-fA-F]*/, 'number'], + [/[$][+-]*\d*(\.\d*)?/, 'number'], + [/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/, 'number'], + ], + strings: [ + [/N'/, { token: 'string', next: '@string' }], + [/'/, { token: 'string', next: '@string' }], + ], + string: [ + [/[^']+/, 'string'], + [/''/, 'string'], + [/'/, { token: 'string', next: '@pop' }], + ], + comment: [ + [/[^\/*]+/, 'comment'], + [/\*\//, 'comment', '@pop'], + [/[\/*]/, 'comment'], + ], + }, +} as monaco.languages.IMonarchLanguage; + +monaco.languages.register({ + id: ID, +}); diff --git a/packages/osd-monaco/src/xjson/lexer_rules/opensearchsql.ts b/packages/osd-monaco/src/xjson/lexer_rules/opensearchsql.ts index b204c63e83c4..0ff29b71c09d 100644 --- a/packages/osd-monaco/src/xjson/lexer_rules/opensearchsql.ts +++ b/packages/osd-monaco/src/xjson/lexer_rules/opensearchsql.ts @@ -155,3 +155,7 @@ export const lexerRules = { ], }, } as monaco.languages.IMonarchLanguage; + +monaco.languages.register({ + id: ID, +}); diff --git a/src/plugins/data/public/antlr/dql/code_completion.test.ts b/src/plugins/data/public/antlr/dql/code_completion.test.ts index 583976126965..7a4efe719cc1 100644 --- a/src/plugins/data/public/antlr/dql/code_completion.test.ts +++ b/src/plugins/data/public/antlr/dql/code_completion.test.ts @@ -174,32 +174,31 @@ const testingIndex = ({ } as unknown) as IndexPattern; const booleanOperatorSuggestions = [ - { end: -1, start: -1, text: 'or', type: 17 }, - { end: -1, start: -1, text: 'and', type: 17 }, + { text: 'or', type: 17, detail: 'Keyword' }, + { text: 'and', type: 17, detail: 'Keyword' }, ]; -const notOperatorSuggestion = { text: 'not', type: 17, end: -1, start: -1 }; +const notOperatorSuggestion = { text: 'not', type: 17, detail: 'Keyword' }; const fieldNameSuggestions: Array<{ text: string; type: number; insertText?: string; - end: number; - start: number; + detail: string; }> = [ - { text: 'Carrier', type: 3, insertText: 'Carrier: ', end: -1, start: -1 }, - { text: 'DestCityName', type: 3, insertText: 'DestCityName: ', end: -1, start: -1 }, - { text: 'DestCountry', type: 3, insertText: 'DestCountry: ', end: -1, start: -1 }, - { text: 'DestWeather', type: 3, insertText: 'DestWeather: ', end: -1, start: -1 }, - { text: 'DistanceMiles', type: 3, insertText: 'DistanceMiles: ', end: -1, start: -1 }, - { text: 'FlightDelay', type: 3, insertText: 'FlightDelay: ', end: -1, start: -1 }, - { text: 'FlightNum', type: 3, insertText: 'FlightNum: ', end: -1, start: -1 }, - { text: 'OriginWeather', type: 3, insertText: 'OriginWeather: ', end: -1, start: -1 }, - { text: '_id', type: 3, insertText: '_id: ', end: -1, start: -1 }, - { text: '_index', type: 3, insertText: '_index: ', end: -1, start: -1 }, - { text: '_score', type: 3, insertText: '_score: ', end: -1, start: -1 }, - { text: '_source', type: 3, insertText: '_source: ', end: -1, start: -1 }, - { text: '_type', type: 3, insertText: '_type: ', end: -1, start: -1 }, + { text: 'Carrier', type: 3, insertText: 'Carrier: ', detail: 'Field: keyword' }, + { text: 'DestCityName', type: 3, insertText: 'DestCityName: ', detail: 'Field: keyword' }, + { text: 'DestCountry', type: 3, insertText: 'DestCountry: ', detail: 'Field: keyword' }, + { text: 'DestWeather', type: 3, insertText: 'DestWeather: ', detail: 'Field: keyword' }, + { text: 'DistanceMiles', type: 3, insertText: 'DistanceMiles: ', detail: 'Field: float' }, + { text: 'FlightDelay', type: 3, insertText: 'FlightDelay: ', detail: 'Field: boolean' }, + { text: 'FlightNum', type: 3, insertText: 'FlightNum: ', detail: 'Field: keyword' }, + { text: 'OriginWeather', type: 3, insertText: 'OriginWeather: ', detail: 'Field: keyword' }, + { text: '_id', type: 3, insertText: '_id: ', detail: 'Field: _id' }, + { text: '_index', type: 3, insertText: '_index: ', detail: 'Field: _index' }, + { text: '_score', type: 3, insertText: '_score: ', detail: 'Field: number' }, + { text: '_source', type: 3, insertText: '_source: ', detail: 'Field: _source' }, + { text: '_type', type: 3, insertText: '_type: ', detail: 'Field: _type' }, ]; const fieldNameWithNotSuggestions = fieldNameSuggestions.concat(notOperatorSuggestion); @@ -212,31 +211,34 @@ const carrierValues = [ ]; const allCarrierValueSuggestions = [ - { text: 'Logstash Airways', type: 13, start: -1, end: -1 }, - { text: 'BeatsWest', type: 13, start: -1, end: -1 }, + { text: 'Logstash Airways', type: 13, detail: 'Value' }, + { text: 'BeatsWest', type: 13, detail: 'Value' }, { text: 'OpenSearch Dashboards Airlines', type: 13, - start: -1, - end: -1, + detail: 'Value', }, - { text: 'OpenSearch-Air', type: 13, start: -1, end: -1 }, + { text: 'OpenSearch-Air', type: 13, detail: 'Value' }, ]; const carrierWithNotSuggestions = allCarrierValueSuggestions.concat(notOperatorSuggestion); -const logCarrierValueSuggestion = [{ text: 'Logstash Airways', type: 13, start: -1, end: -1 }]; +const logCarrierValueSuggestion = [{ text: 'Logstash Airways', type: 13, detail: 'Value' }]; const openCarrierValueSuggestion = [ { text: 'OpenSearch Dashboards Airlines', type: 13, - start: -1, - end: -1, + detail: 'Value', }, - { text: 'OpenSearch-Air', type: 13, start: -1, end: -1 }, + { text: 'OpenSearch-Air', type: 13, detail: 'Value' }, ]; +const addPositionToValue = (vals: any, start: number, end: number) => + vals.map((val: any) => { + return { ...val, replacePosition: new monaco.Range(1, start, 1, end) }; + }); + /** * Actual Tests */ @@ -388,32 +390,40 @@ describe('Test basic value suggestions', () => { }); it('suggest token search value for field', async () => { - expect(await getSuggestionsAtEnd('Carrier: ')).toStrictEqual(allCarrierValueSuggestions); + expect(await getSuggestionsAtEnd('Carrier: ')).toStrictEqual( + addPositionToValue(allCarrierValueSuggestions, 10, 10) + ); }); it('suggest value for field without surrounding space', async () => { - expect(await getSuggestionsAtEnd('Carrier:')).toStrictEqual(allCarrierValueSuggestions); + expect(await getSuggestionsAtEnd('Carrier:')).toStrictEqual( + addPositionToValue(allCarrierValueSuggestions, 9, 9) + ); }); it('suggest value from partial value', async () => { - expect(await getSuggestionsAtEnd('Carrier: Log')).toStrictEqual(logCarrierValueSuggestion); + expect(await getSuggestionsAtEnd('Carrier: Log')).toStrictEqual( + addPositionToValue(logCarrierValueSuggestion, 10, 13) + ); }); it('suggest multiple values from partial value', async () => { - expect(await getSuggestionsAtEnd('Carrier: Open')).toStrictEqual(openCarrierValueSuggestion); + expect(await getSuggestionsAtEnd('Carrier: Open')).toStrictEqual( + addPositionToValue(openCarrierValueSuggestion, 10, 14) + ); }); testAroundClosing( 'Carrier: ', ['"', '"'], 'should suggest within phrase', - allCarrierValueSuggestions + addPositionToValue(allCarrierValueSuggestions, 11, 11) ); it('suggest rest of partial value within quotes', async () => { const query = 'Carrier: "OpenSearch"'; expect(await getSuggestionsAtPos(query, query.length)).toStrictEqual( - openCarrierValueSuggestion + addPositionToValue(openCarrierValueSuggestion, 11, 21) ); }); @@ -421,17 +431,22 @@ describe('Test basic value suggestions', () => { }); describe('Test value suggestion with multiple terms', () => { + it('should suggest after one field value expression', async () => { + expect(await getSuggestionsAtEnd('Carrier: BeatsWest or Carrier: ')).toStrictEqual( + addPositionToValue(allCarrierValueSuggestions, 32, 32) + ); + }); + testAroundClosing( 'Carrier: BeatsWest or Carrier: ', ['"', '"'], 'should suggest after one field value expression', - allCarrierValueSuggestions, - true + addPositionToValue(allCarrierValueSuggestions, 33, 33) ); it('should suggest after field value expression and partial value', async () => { expect(await getSuggestionsAtEnd('Carrier: BeatsWest or Carrier: Open')).toStrictEqual( - openCarrierValueSuggestion + addPositionToValue(openCarrierValueSuggestion, 32, 36) ); }); @@ -439,7 +454,7 @@ describe('Test value suggestion with multiple terms', () => { 'Carrier: BeatsWest or Carrier: "Open', [undefined, '"'], 'should suggest after field value expression in partial value quotes', - openCarrierValueSuggestion, + addPositionToValue(openCarrierValueSuggestion, 33, 37), true ); }); @@ -449,50 +464,64 @@ describe('Test group value suggestions', () => { 'Carrier: ', ['(', ')'], 'should suggest within grouping', - carrierWithNotSuggestions + addPositionToValue(allCarrierValueSuggestions, 11, 11).concat(notOperatorSuggestion) ); testAroundClosing( 'Carrier: (', ['"', '"'], 'should suggest within grouping and phrase', - allCarrierValueSuggestions + addPositionToValue(allCarrierValueSuggestions, 12, 12) ); testAroundClosing( 'Carrier: ("', [undefined, '")'], 'should suggest within closed grouping and phrase', - allCarrierValueSuggestions + addPositionToValue(allCarrierValueSuggestions, 13, 13) ); testAroundClosing( 'Carrier: (BeatsWest or ', [undefined, ')'], 'should suggest after grouping with term', - carrierWithNotSuggestions, + addPositionToValue(allCarrierValueSuggestions, 24, 24).concat(notOperatorSuggestion), true ); - testAroundClosing( - 'Carrier: (BeatsWest or ', - ['"', '")'], - 'should suggest in phrase after grouping with term', - allCarrierValueSuggestions - ); + it('should suggest in phrase after grouping with term - opened', async () => { + const currQuery = 'Carrier: (BeatsWest or "'; + expect(await getSuggestionsAtEnd(currQuery)).toStrictEqual( + addPositionToValue(allCarrierValueSuggestions, 25, 25) + ); + }); + + it('should suggest in phrase after grouping with term - closed', async () => { + const currQuery = 'Carrier: (BeatsWest or "")'; + expect(await getSuggestionsAtPos(currQuery, 25)).toStrictEqual( + addPositionToValue(allCarrierValueSuggestions, 25, 25) + ); + }); testAroundClosing( 'Carrier: ("BeatsWest" or ', [undefined, ')'], 'should suggest after grouping with phrase', - carrierWithNotSuggestions, + addPositionToValue(allCarrierValueSuggestions, 26, 26).concat(notOperatorSuggestion), true ); - testAroundClosing( - 'Carrier: ("BeatsWest" or ', - ['"', '")'], - 'should suggest in phrase after grouping with phrase', - allCarrierValueSuggestions - ); + it('should suggest in phrase after grouping with phrase - opened', async () => { + const currQuery = 'Carrier: ("BeatsWest" or "'; + expect(await getSuggestionsAtEnd(currQuery)).toStrictEqual( + addPositionToValue(allCarrierValueSuggestions, 27, 27) + ); + }); + + it('should suggest in phrase after grouping with phrase - closed', async () => { + const currQuery = 'Carrier: ("BeatsWest" or "")'; + expect(await getSuggestionsAtPos(currQuery, 27)).toStrictEqual( + addPositionToValue(allCarrierValueSuggestions, 27, 27) + ); + }); }); diff --git a/src/plugins/data/public/antlr/dql/code_completion.ts b/src/plugins/data/public/antlr/dql/code_completion.ts index 025c2118fbc7..a14310f56979 100644 --- a/src/plugins/data/public/antlr/dql/code_completion.ts +++ b/src/plugins/data/public/antlr/dql/code_completion.ts @@ -18,7 +18,8 @@ import { IndexPattern, IndexPatternField } from '../../index_patterns'; import { QuerySuggestion, QuerySuggestionGetFnArgs } from '../../autocomplete'; import { DQLParserVisitor } from './.generated/DQLParserVisitor'; import { IDataPluginServices } from '../..'; -import { getQueryService } from '../../services'; +import { fetchFieldSuggestions } from '../shared/utils'; +import { SuggestionItemDetailsTags } from '../shared/constants'; const findCursorIndex = ( tokenStream: TokenStream, @@ -41,26 +42,6 @@ const findCursorIndex = ( return undefined; }; -const findFieldSuggestions = (indexPattern: IndexPattern) => { - const fieldNames: string[] = indexPattern.fields - .filter((idxField: IndexPatternField) => !idxField?.subType) // filter removed .keyword fields - .map((idxField: { name: string }) => { - return idxField.name; - }); - - const fieldSuggestions: QuerySuggestion[] = fieldNames.map((field: string) => { - return { - text: field, - type: monaco.languages.CompletionItemKind.Field, - insertText: `${field}: `, - start: -1, - end: -1, - }; - }); - - return fieldSuggestions; -}; - const findValueSuggestions = async ( index: IndexPattern, field: string, @@ -154,7 +135,7 @@ export const getSuggestions = async ({ // check to see if field rule is a candidate. if so, suggest field names if (candidates.rules.has(DQLParser.RULE_field)) { - completions.push(...findFieldSuggestions(indexPattern)); + completions.push(...fetchFieldSuggestions(indexPattern, (f) => `${f}: `)); } interface FoundLastValue { @@ -259,8 +240,13 @@ export const getSuggestions = async ({ return { text: val, type: monaco.languages.CompletionItemKind.Value, - start: -1, - end: -1, + detail: SuggestionItemDetailsTags.Value, + replacePosition: new monaco.Range( + cursorLine, + cursorColumn - lastValue.length + 1, + cursorLine, + cursorColumn + 1 + ), }; }) ); @@ -279,8 +265,7 @@ export const getSuggestions = async ({ completions.push({ text: tokenSymbolName, type: monaco.languages.CompletionItemKind.Keyword, - start: -1, - end: -1, + detail: SuggestionItemDetailsTags.Keyword, }); } }); diff --git a/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.interp b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.interp new file mode 100644 index 000000000000..2dded62b3c4c --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.interp @@ -0,0 +1,1033 @@ +token literal names: +null +null +'SEARCH' +'DESCRIBE' +'SHOW' +'FROM' +'WHERE' +'FIELDS' +'RENAME' +'STATS' +'DEDUP' +'SORT' +'EVAL' +'HEAD' +'TOP' +'RARE' +'PARSE' +'METHOD' +'REGEX' +'PUNCT' +'GROK' +'PATTERN' +'PATTERNS' +'NEW_FIELD' +'KMEANS' +'AD' +'ML' +'AS' +'BY' +'SOURCE' +'INDEX' +'D' +'DESC' +'DATASOURCES' +'SORTBY' +'AUTO' +'STR' +'IP' +'NUM' +'KEEPEMPTY' +'CONSECUTIVE' +'DEDUP_SPLITVALUES' +'PARTITIONS' +'ALLNUM' +'DELIM' +'CENTROIDS' +'ITERATIONS' +'DISTANCE_TYPE' +'NUMBER_OF_TREES' +'SHINGLE_SIZE' +'SAMPLE_SIZE' +'OUTPUT_AFTER' +'TIME_DECAY' +'ANOMALY_RATE' +'CATEGORY_FIELD' +'TIME_FIELD' +'TIME_ZONE' +'TRAINING_DATA_SIZE' +'ANOMALY_SCORE_THRESHOLD' +'CASE' +'IN' +'NOT' +'OR' +'AND' +'XOR' +'TRUE' +'FALSE' +'REGEXP' +'CONVERT_TZ' +'DATETIME' +'DAY' +'DAY_HOUR' +'DAY_MICROSECOND' +'DAY_MINUTE' +'DAY_OF_YEAR' +'DAY_SECOND' +'HOUR' +'HOUR_MICROSECOND' +'HOUR_MINUTE' +'HOUR_OF_DAY' +'HOUR_SECOND' +'INTERVAL' +'MICROSECOND' +'MILLISECOND' +'MINUTE' +'MINUTE_MICROSECOND' +'MINUTE_OF_DAY' +'MINUTE_OF_HOUR' +'MINUTE_SECOND' +'MONTH' +'MONTH_OF_YEAR' +'QUARTER' +'SECOND' +'SECOND_MICROSECOND' +'SECOND_OF_MINUTE' +'WEEK' +'WEEK_OF_YEAR' +'YEAR' +'YEAR_MONTH' +'DATAMODEL' +'LOOKUP' +'SAVEDSEARCH' +'INT' +'INTEGER' +'DOUBLE' +'LONG' +'FLOAT' +'STRING' +'BOOLEAN' +'|' +',' +'.' +'=' +'>' +'<' +null +null +null +'+' +'-' +'*' +'/' +'%' +'!' +':' +'(' +')' +'[' +']' +'\'' +'"' +'`' +'~' +'&' +'^' +'AVG' +'COUNT' +'DISTINCT_COUNT' +'ESTDC' +'ESTDC_ERROR' +'MAX' +'MEAN' +'MEDIAN' +'MIN' +'MODE' +'RANGE' +'STDEV' +'STDEVP' +'SUM' +'SUMSQ' +'VAR_SAMP' +'VAR_POP' +'STDDEV_SAMP' +'STDDEV_POP' +'PERCENTILE' +'TAKE' +'FIRST' +'LAST' +'LIST' +'VALUES' +'EARLIEST' +'EARLIEST_TIME' +'LATEST' +'LATEST_TIME' +'PER_DAY' +'PER_HOUR' +'PER_MINUTE' +'PER_SECOND' +'RATE' +'SPARKLINE' +'C' +'DC' +'ABS' +'CBRT' +'CEIL' +'CEILING' +'CONV' +'CRC32' +'E' +'EXP' +'FLOOR' +'LN' +'LOG' +'LOG10' +'LOG2' +'MOD' +'PI' +'POSITION' +'POW' +'POWER' +'RAND' +'ROUND' +'SIGN' +'SQRT' +'TRUNCATE' +'ACOS' +'ASIN' +'ATAN' +'ATAN2' +'COS' +'COT' +'DEGREES' +'RADIANS' +'SIN' +'TAN' +'ADDDATE' +'ADDTIME' +'CURDATE' +'CURRENT_DATE' +'CURRENT_TIME' +'CURRENT_TIMESTAMP' +'CURTIME' +'DATE' +'DATEDIFF' +'DATE_ADD' +'DATE_FORMAT' +'DATE_SUB' +'DAYNAME' +'DAYOFMONTH' +'DAYOFWEEK' +'DAYOFYEAR' +'DAY_OF_MONTH' +'DAY_OF_WEEK' +'EXTRACT' +'FROM_DAYS' +'FROM_UNIXTIME' +'GET_FORMAT' +'LAST_DAY' +'LOCALTIME' +'LOCALTIMESTAMP' +'MAKEDATE' +'MAKETIME' +'MONTHNAME' +'NOW' +'PERIOD_ADD' +'PERIOD_DIFF' +'SEC_TO_TIME' +'STR_TO_DATE' +'SUBDATE' +'SUBTIME' +'SYSDATE' +'TIME' +'TIMEDIFF' +'TIMESTAMP' +'TIMESTAMPADD' +'TIMESTAMPDIFF' +'TIME_FORMAT' +'TIME_TO_SEC' +'TO_DAYS' +'TO_SECONDS' +'UNIX_TIMESTAMP' +'UTC_DATE' +'UTC_TIME' +'UTC_TIMESTAMP' +'WEEKDAY' +'YEARWEEK' +'SUBSTR' +'SUBSTRING' +'LTRIM' +'RTRIM' +'TRIM' +'TO' +'LOWER' +'UPPER' +'CONCAT' +'CONCAT_WS' +'LENGTH' +'STRCMP' +'RIGHT' +'LEFT' +'ASCII' +'LOCATE' +'REPLACE' +'REVERSE' +'CAST' +'LIKE' +'ISNULL' +'ISNOTNULL' +'IFNULL' +'NULLIF' +'IF' +'TYPEOF' +'MATCH' +'MATCH_PHRASE' +'MATCH_PHRASE_PREFIX' +'MATCH_BOOL_PREFIX' +'SIMPLE_QUERY_STRING' +'MULTI_MATCH' +'QUERY_STRING' +'ALLOW_LEADING_WILDCARD' +'ANALYZE_WILDCARD' +'ANALYZER' +'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY' +'BOOST' +'CUTOFF_FREQUENCY' +'DEFAULT_FIELD' +'DEFAULT_OPERATOR' +'ENABLE_POSITION_INCREMENTS' +'ESCAPE' +'FLAGS' +'FUZZY_MAX_EXPANSIONS' +'FUZZY_PREFIX_LENGTH' +'FUZZY_TRANSPOSITIONS' +'FUZZY_REWRITE' +'FUZZINESS' +'LENIENT' +'LOW_FREQ_OPERATOR' +'MAX_DETERMINIZED_STATES' +'MAX_EXPANSIONS' +'MINIMUM_SHOULD_MATCH' +'OPERATOR' +'PHRASE_SLOP' +'PREFIX_LENGTH' +'QUOTE_ANALYZER' +'QUOTE_FIELD_SUFFIX' +'REWRITE' +'SLOP' +'TIE_BREAKER' +'TYPE' +'ZERO_TERMS_QUERY' +'SPAN' +'MS' +'S' +'M' +'H' +'W' +'Q' +'Y' +null +null +null +null +null +null +null +null +null + +token symbolic names: +null +SPACE +SEARCH +DESCRIBE +SHOW +FROM +WHERE +FIELDS +RENAME +STATS +DEDUP +SORT +EVAL +HEAD +TOP +RARE +PARSE +METHOD +REGEX +PUNCT +GROK +PATTERN +PATTERNS +NEW_FIELD +KMEANS +AD +ML +AS +BY +SOURCE +INDEX +D +DESC +DATASOURCES +SORTBY +AUTO +STR +IP +NUM +KEEPEMPTY +CONSECUTIVE +DEDUP_SPLITVALUES +PARTITIONS +ALLNUM +DELIM +CENTROIDS +ITERATIONS +DISTANCE_TYPE +NUMBER_OF_TREES +SHINGLE_SIZE +SAMPLE_SIZE +OUTPUT_AFTER +TIME_DECAY +ANOMALY_RATE +CATEGORY_FIELD +TIME_FIELD +TIME_ZONE +TRAINING_DATA_SIZE +ANOMALY_SCORE_THRESHOLD +CASE +IN +NOT +OR +AND +XOR +TRUE +FALSE +REGEXP +CONVERT_TZ +DATETIME +DAY +DAY_HOUR +DAY_MICROSECOND +DAY_MINUTE +DAY_OF_YEAR +DAY_SECOND +HOUR +HOUR_MICROSECOND +HOUR_MINUTE +HOUR_OF_DAY +HOUR_SECOND +INTERVAL +MICROSECOND +MILLISECOND +MINUTE +MINUTE_MICROSECOND +MINUTE_OF_DAY +MINUTE_OF_HOUR +MINUTE_SECOND +MONTH +MONTH_OF_YEAR +QUARTER +SECOND +SECOND_MICROSECOND +SECOND_OF_MINUTE +WEEK +WEEK_OF_YEAR +YEAR +YEAR_MONTH +DATAMODEL +LOOKUP +SAVEDSEARCH +INT +INTEGER +DOUBLE +LONG +FLOAT +STRING +BOOLEAN +PIPE +COMMA +DOT +EQUAL +GREATER +LESS +NOT_GREATER +NOT_LESS +NOT_EQUAL +PLUS +MINUS +STAR +DIVIDE +MODULE +EXCLAMATION_SYMBOL +COLON +LT_PRTHS +RT_PRTHS +LT_SQR_PRTHS +RT_SQR_PRTHS +SINGLE_QUOTE +DOUBLE_QUOTE +BACKTICK +BIT_NOT_OP +BIT_AND_OP +BIT_XOR_OP +AVG +COUNT +DISTINCT_COUNT +ESTDC +ESTDC_ERROR +MAX +MEAN +MEDIAN +MIN +MODE +RANGE +STDEV +STDEVP +SUM +SUMSQ +VAR_SAMP +VAR_POP +STDDEV_SAMP +STDDEV_POP +PERCENTILE +TAKE +FIRST +LAST +LIST +VALUES +EARLIEST +EARLIEST_TIME +LATEST +LATEST_TIME +PER_DAY +PER_HOUR +PER_MINUTE +PER_SECOND +RATE +SPARKLINE +C +DC +ABS +CBRT +CEIL +CEILING +CONV +CRC32 +E +EXP +FLOOR +LN +LOG +LOG10 +LOG2 +MOD +PI +POSITION +POW +POWER +RAND +ROUND +SIGN +SQRT +TRUNCATE +ACOS +ASIN +ATAN +ATAN2 +COS +COT +DEGREES +RADIANS +SIN +TAN +ADDDATE +ADDTIME +CURDATE +CURRENT_DATE +CURRENT_TIME +CURRENT_TIMESTAMP +CURTIME +DATE +DATEDIFF +DATE_ADD +DATE_FORMAT +DATE_SUB +DAYNAME +DAYOFMONTH +DAYOFWEEK +DAYOFYEAR +DAY_OF_MONTH +DAY_OF_WEEK +EXTRACT +FROM_DAYS +FROM_UNIXTIME +GET_FORMAT +LAST_DAY +LOCALTIME +LOCALTIMESTAMP +MAKEDATE +MAKETIME +MONTHNAME +NOW +PERIOD_ADD +PERIOD_DIFF +SEC_TO_TIME +STR_TO_DATE +SUBDATE +SUBTIME +SYSDATE +TIME +TIMEDIFF +TIMESTAMP +TIMESTAMPADD +TIMESTAMPDIFF +TIME_FORMAT +TIME_TO_SEC +TO_DAYS +TO_SECONDS +UNIX_TIMESTAMP +UTC_DATE +UTC_TIME +UTC_TIMESTAMP +WEEKDAY +YEARWEEK +SUBSTR +SUBSTRING +LTRIM +RTRIM +TRIM +TO +LOWER +UPPER +CONCAT +CONCAT_WS +LENGTH +STRCMP +RIGHT +LEFT +ASCII +LOCATE +REPLACE +REVERSE +CAST +LIKE +ISNULL +ISNOTNULL +IFNULL +NULLIF +IF +TYPEOF +MATCH +MATCH_PHRASE +MATCH_PHRASE_PREFIX +MATCH_BOOL_PREFIX +SIMPLE_QUERY_STRING +MULTI_MATCH +QUERY_STRING +ALLOW_LEADING_WILDCARD +ANALYZE_WILDCARD +ANALYZER +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY +BOOST +CUTOFF_FREQUENCY +DEFAULT_FIELD +DEFAULT_OPERATOR +ENABLE_POSITION_INCREMENTS +ESCAPE +FLAGS +FUZZY_MAX_EXPANSIONS +FUZZY_PREFIX_LENGTH +FUZZY_TRANSPOSITIONS +FUZZY_REWRITE +FUZZINESS +LENIENT +LOW_FREQ_OPERATOR +MAX_DETERMINIZED_STATES +MAX_EXPANSIONS +MINIMUM_SHOULD_MATCH +OPERATOR +PHRASE_SLOP +PREFIX_LENGTH +QUOTE_ANALYZER +QUOTE_FIELD_SUFFIX +REWRITE +SLOP +TIE_BREAKER +TYPE +ZERO_TERMS_QUERY +SPAN +MS +S +M +H +W +Q +Y +ID +CLUSTER +INTEGER_LITERAL +DECIMAL_LITERAL +ID_DATE_SUFFIX +DQUOTA_STRING +SQUOTA_STRING +BQUOTA_STRING +ERROR_RECOGNITION + +rule names: +SPACE +SEARCH +DESCRIBE +SHOW +FROM +WHERE +FIELDS +RENAME +STATS +DEDUP +SORT +EVAL +HEAD +TOP +RARE +PARSE +METHOD +REGEX +PUNCT +GROK +PATTERN +PATTERNS +NEW_FIELD +KMEANS +AD +ML +AS +BY +SOURCE +INDEX +D +DESC +DATASOURCES +SORTBY +AUTO +STR +IP +NUM +KEEPEMPTY +CONSECUTIVE +DEDUP_SPLITVALUES +PARTITIONS +ALLNUM +DELIM +CENTROIDS +ITERATIONS +DISTANCE_TYPE +NUMBER_OF_TREES +SHINGLE_SIZE +SAMPLE_SIZE +OUTPUT_AFTER +TIME_DECAY +ANOMALY_RATE +CATEGORY_FIELD +TIME_FIELD +TIME_ZONE +TRAINING_DATA_SIZE +ANOMALY_SCORE_THRESHOLD +CASE +IN +NOT +OR +AND +XOR +TRUE +FALSE +REGEXP +CONVERT_TZ +DATETIME +DAY +DAY_HOUR +DAY_MICROSECOND +DAY_MINUTE +DAY_OF_YEAR +DAY_SECOND +HOUR +HOUR_MICROSECOND +HOUR_MINUTE +HOUR_OF_DAY +HOUR_SECOND +INTERVAL +MICROSECOND +MILLISECOND +MINUTE +MINUTE_MICROSECOND +MINUTE_OF_DAY +MINUTE_OF_HOUR +MINUTE_SECOND +MONTH +MONTH_OF_YEAR +QUARTER +SECOND +SECOND_MICROSECOND +SECOND_OF_MINUTE +WEEK +WEEK_OF_YEAR +YEAR +YEAR_MONTH +DATAMODEL +LOOKUP +SAVEDSEARCH +INT +INTEGER +DOUBLE +LONG +FLOAT +STRING +BOOLEAN +PIPE +COMMA +DOT +EQUAL +GREATER +LESS +NOT_GREATER +NOT_LESS +NOT_EQUAL +PLUS +MINUS +STAR +DIVIDE +MODULE +EXCLAMATION_SYMBOL +COLON +LT_PRTHS +RT_PRTHS +LT_SQR_PRTHS +RT_SQR_PRTHS +SINGLE_QUOTE +DOUBLE_QUOTE +BACKTICK +BIT_NOT_OP +BIT_AND_OP +BIT_XOR_OP +AVG +COUNT +DISTINCT_COUNT +ESTDC +ESTDC_ERROR +MAX +MEAN +MEDIAN +MIN +MODE +RANGE +STDEV +STDEVP +SUM +SUMSQ +VAR_SAMP +VAR_POP +STDDEV_SAMP +STDDEV_POP +PERCENTILE +TAKE +FIRST +LAST +LIST +VALUES +EARLIEST +EARLIEST_TIME +LATEST +LATEST_TIME +PER_DAY +PER_HOUR +PER_MINUTE +PER_SECOND +RATE +SPARKLINE +C +DC +ABS +CBRT +CEIL +CEILING +CONV +CRC32 +E +EXP +FLOOR +LN +LOG +LOG10 +LOG2 +MOD +PI +POSITION +POW +POWER +RAND +ROUND +SIGN +SQRT +TRUNCATE +ACOS +ASIN +ATAN +ATAN2 +COS +COT +DEGREES +RADIANS +SIN +TAN +ADDDATE +ADDTIME +CURDATE +CURRENT_DATE +CURRENT_TIME +CURRENT_TIMESTAMP +CURTIME +DATE +DATEDIFF +DATE_ADD +DATE_FORMAT +DATE_SUB +DAYNAME +DAYOFMONTH +DAYOFWEEK +DAYOFYEAR +DAY_OF_MONTH +DAY_OF_WEEK +EXTRACT +FROM_DAYS +FROM_UNIXTIME +GET_FORMAT +LAST_DAY +LOCALTIME +LOCALTIMESTAMP +MAKEDATE +MAKETIME +MONTHNAME +NOW +PERIOD_ADD +PERIOD_DIFF +SEC_TO_TIME +STR_TO_DATE +SUBDATE +SUBTIME +SYSDATE +TIME +TIMEDIFF +TIMESTAMP +TIMESTAMPADD +TIMESTAMPDIFF +TIME_FORMAT +TIME_TO_SEC +TO_DAYS +TO_SECONDS +UNIX_TIMESTAMP +UTC_DATE +UTC_TIME +UTC_TIMESTAMP +WEEKDAY +YEARWEEK +SUBSTR +SUBSTRING +LTRIM +RTRIM +TRIM +TO +LOWER +UPPER +CONCAT +CONCAT_WS +LENGTH +STRCMP +RIGHT +LEFT +ASCII +LOCATE +REPLACE +REVERSE +CAST +LIKE +ISNULL +ISNOTNULL +IFNULL +NULLIF +IF +TYPEOF +MATCH +MATCH_PHRASE +MATCH_PHRASE_PREFIX +MATCH_BOOL_PREFIX +SIMPLE_QUERY_STRING +MULTI_MATCH +QUERY_STRING +ALLOW_LEADING_WILDCARD +ANALYZE_WILDCARD +ANALYZER +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY +BOOST +CUTOFF_FREQUENCY +DEFAULT_FIELD +DEFAULT_OPERATOR +ENABLE_POSITION_INCREMENTS +ESCAPE +FLAGS +FUZZY_MAX_EXPANSIONS +FUZZY_PREFIX_LENGTH +FUZZY_TRANSPOSITIONS +FUZZY_REWRITE +FUZZINESS +LENIENT +LOW_FREQ_OPERATOR +MAX_DETERMINIZED_STATES +MAX_EXPANSIONS +MINIMUM_SHOULD_MATCH +OPERATOR +PHRASE_SLOP +PREFIX_LENGTH +QUOTE_ANALYZER +QUOTE_FIELD_SUFFIX +REWRITE +SLOP +TIE_BREAKER +TYPE +ZERO_TERMS_QUERY +SPAN +MS +S +M +H +W +Q +Y +ID +CLUSTER +INTEGER_LITERAL +DECIMAL_LITERAL +DATE_SUFFIX +ID_LITERAL +CLUSTER_PREFIX_LITERAL +ID_DATE_SUFFIX +DQUOTA_STRING +SQUOTA_STRING +BQUOTA_STRING +DEC_DIGIT +ERROR_RECOGNITION + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN +null +null +WHITESPACE +ERRORCHANNEL + +mode names: +DEFAULT_MODE + +atn: +[4, 0, 336, 3509, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 2, 217, 7, 217, 2, 218, 7, 218, 2, 219, 7, 219, 2, 220, 7, 220, 2, 221, 7, 221, 2, 222, 7, 222, 2, 223, 7, 223, 2, 224, 7, 224, 2, 225, 7, 225, 2, 226, 7, 226, 2, 227, 7, 227, 2, 228, 7, 228, 2, 229, 7, 229, 2, 230, 7, 230, 2, 231, 7, 231, 2, 232, 7, 232, 2, 233, 7, 233, 2, 234, 7, 234, 2, 235, 7, 235, 2, 236, 7, 236, 2, 237, 7, 237, 2, 238, 7, 238, 2, 239, 7, 239, 2, 240, 7, 240, 2, 241, 7, 241, 2, 242, 7, 242, 2, 243, 7, 243, 2, 244, 7, 244, 2, 245, 7, 245, 2, 246, 7, 246, 2, 247, 7, 247, 2, 248, 7, 248, 2, 249, 7, 249, 2, 250, 7, 250, 2, 251, 7, 251, 2, 252, 7, 252, 2, 253, 7, 253, 2, 254, 7, 254, 2, 255, 7, 255, 2, 256, 7, 256, 2, 257, 7, 257, 2, 258, 7, 258, 2, 259, 7, 259, 2, 260, 7, 260, 2, 261, 7, 261, 2, 262, 7, 262, 2, 263, 7, 263, 2, 264, 7, 264, 2, 265, 7, 265, 2, 266, 7, 266, 2, 267, 7, 267, 2, 268, 7, 268, 2, 269, 7, 269, 2, 270, 7, 270, 2, 271, 7, 271, 2, 272, 7, 272, 2, 273, 7, 273, 2, 274, 7, 274, 2, 275, 7, 275, 2, 276, 7, 276, 2, 277, 7, 277, 2, 278, 7, 278, 2, 279, 7, 279, 2, 280, 7, 280, 2, 281, 7, 281, 2, 282, 7, 282, 2, 283, 7, 283, 2, 284, 7, 284, 2, 285, 7, 285, 2, 286, 7, 286, 2, 287, 7, 287, 2, 288, 7, 288, 2, 289, 7, 289, 2, 290, 7, 290, 2, 291, 7, 291, 2, 292, 7, 292, 2, 293, 7, 293, 2, 294, 7, 294, 2, 295, 7, 295, 2, 296, 7, 296, 2, 297, 7, 297, 2, 298, 7, 298, 2, 299, 7, 299, 2, 300, 7, 300, 2, 301, 7, 301, 2, 302, 7, 302, 2, 303, 7, 303, 2, 304, 7, 304, 2, 305, 7, 305, 2, 306, 7, 306, 2, 307, 7, 307, 2, 308, 7, 308, 2, 309, 7, 309, 2, 310, 7, 310, 2, 311, 7, 311, 2, 312, 7, 312, 2, 313, 7, 313, 2, 314, 7, 314, 2, 315, 7, 315, 2, 316, 7, 316, 2, 317, 7, 317, 2, 318, 7, 318, 2, 319, 7, 319, 2, 320, 7, 320, 2, 321, 7, 321, 2, 322, 7, 322, 2, 323, 7, 323, 2, 324, 7, 324, 2, 325, 7, 325, 2, 326, 7, 326, 2, 327, 7, 327, 2, 328, 7, 328, 2, 329, 7, 329, 2, 330, 7, 330, 2, 331, 7, 331, 2, 332, 7, 332, 2, 333, 7, 333, 2, 334, 7, 334, 2, 335, 7, 335, 2, 336, 7, 336, 2, 337, 7, 337, 2, 338, 7, 338, 2, 339, 7, 339, 1, 0, 4, 0, 683, 8, 0, 11, 0, 12, 0, 684, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 109, 1, 109, 1, 110, 1, 110, 1, 111, 1, 111, 1, 112, 1, 112, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 118, 1, 118, 1, 119, 1, 119, 1, 120, 1, 120, 1, 121, 1, 121, 1, 122, 1, 122, 1, 123, 1, 123, 1, 124, 1, 124, 1, 125, 1, 125, 1, 126, 1, 126, 1, 127, 1, 127, 1, 128, 1, 128, 1, 129, 1, 129, 1, 130, 1, 130, 1, 131, 1, 131, 1, 132, 1, 132, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 185, 1, 185, 1, 185, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 197, 1, 197, 1, 198, 1, 198, 1, 198, 1, 198, 1, 199, 1, 199, 1, 199, 1, 199, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 201, 1, 201, 1, 201, 1, 201, 1, 201, 1, 202, 1, 202, 1, 202, 1, 202, 1, 203, 1, 203, 1, 203, 1, 203, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 204, 1, 205, 1, 205, 1, 205, 1, 205, 1, 205, 1, 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 206, 1, 206, 1, 206, 1, 206, 1, 206, 1, 206, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 210, 1, 210, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 211, 1, 211, 1, 211, 1, 212, 1, 212, 1, 212, 1, 212, 1, 212, 1, 212, 1, 212, 1, 212, 1, 212, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 215, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 222, 1, 222, 1, 222, 1, 222, 1, 222, 1, 222, 1, 222, 1, 222, 1, 223, 1, 223, 1, 223, 1, 223, 1, 223, 1, 223, 1, 223, 1, 223, 1, 223, 1, 223, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 224, 1, 225, 1, 225, 1, 225, 1, 225, 1, 225, 1, 225, 1, 225, 1, 225, 1, 225, 1, 225, 1, 225, 1, 226, 1, 226, 1, 226, 1, 226, 1, 226, 1, 226, 1, 226, 1, 226, 1, 226, 1, 227, 1, 227, 1, 227, 1, 227, 1, 227, 1, 227, 1, 227, 1, 227, 1, 227, 1, 227, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 228, 1, 229, 1, 229, 1, 229, 1, 229, 1, 229, 1, 229, 1, 229, 1, 229, 1, 229, 1, 230, 1, 230, 1, 230, 1, 230, 1, 230, 1, 230, 1, 230, 1, 230, 1, 230, 1, 231, 1, 231, 1, 231, 1, 231, 1, 231, 1, 231, 1, 231, 1, 231, 1, 231, 1, 231, 1, 232, 1, 232, 1, 232, 1, 232, 1, 233, 1, 233, 1, 233, 1, 233, 1, 233, 1, 233, 1, 233, 1, 233, 1, 233, 1, 233, 1, 233, 1, 234, 1, 234, 1, 234, 1, 234, 1, 234, 1, 234, 1, 234, 1, 234, 1, 234, 1, 234, 1, 234, 1, 234, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 237, 1, 237, 1, 237, 1, 237, 1, 237, 1, 237, 1, 237, 1, 237, 1, 238, 1, 238, 1, 238, 1, 238, 1, 238, 1, 238, 1, 238, 1, 238, 1, 239, 1, 239, 1, 239, 1, 239, 1, 239, 1, 239, 1, 239, 1, 239, 1, 240, 1, 240, 1, 240, 1, 240, 1, 240, 1, 241, 1, 241, 1, 241, 1, 241, 1, 241, 1, 241, 1, 241, 1, 241, 1, 241, 1, 242, 1, 242, 1, 242, 1, 242, 1, 242, 1, 242, 1, 242, 1, 242, 1, 242, 1, 242, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 243, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 244, 1, 245, 1, 245, 1, 245, 1, 245, 1, 245, 1, 245, 1, 245, 1, 245, 1, 245, 1, 245, 1, 245, 1, 245, 1, 246, 1, 246, 1, 246, 1, 246, 1, 246, 1, 246, 1, 246, 1, 246, 1, 246, 1, 246, 1, 246, 1, 246, 1, 247, 1, 247, 1, 247, 1, 247, 1, 247, 1, 247, 1, 247, 1, 247, 1, 248, 1, 248, 1, 248, 1, 248, 1, 248, 1, 248, 1, 248, 1, 248, 1, 248, 1, 248, 1, 248, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 249, 1, 250, 1, 250, 1, 250, 1, 250, 1, 250, 1, 250, 1, 250, 1, 250, 1, 250, 1, 251, 1, 251, 1, 251, 1, 251, 1, 251, 1, 251, 1, 251, 1, 251, 1, 251, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 252, 1, 253, 1, 253, 1, 253, 1, 253, 1, 253, 1, 253, 1, 253, 1, 253, 1, 254, 1, 254, 1, 254, 1, 254, 1, 254, 1, 254, 1, 254, 1, 254, 1, 254, 1, 255, 1, 255, 1, 255, 1, 255, 1, 255, 1, 255, 1, 255, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 257, 1, 257, 1, 257, 1, 257, 1, 257, 1, 257, 1, 258, 1, 258, 1, 258, 1, 258, 1, 258, 1, 258, 1, 259, 1, 259, 1, 259, 1, 259, 1, 259, 1, 260, 1, 260, 1, 260, 1, 261, 1, 261, 1, 261, 1, 261, 1, 261, 1, 261, 1, 262, 1, 262, 1, 262, 1, 262, 1, 262, 1, 262, 1, 263, 1, 263, 1, 263, 1, 263, 1, 263, 1, 263, 1, 263, 1, 264, 1, 264, 1, 264, 1, 264, 1, 264, 1, 264, 1, 264, 1, 264, 1, 264, 1, 264, 1, 265, 1, 265, 1, 265, 1, 265, 1, 265, 1, 265, 1, 265, 1, 266, 1, 266, 1, 266, 1, 266, 1, 266, 1, 266, 1, 266, 1, 267, 1, 267, 1, 267, 1, 267, 1, 267, 1, 267, 1, 268, 1, 268, 1, 268, 1, 268, 1, 268, 1, 269, 1, 269, 1, 269, 1, 269, 1, 269, 1, 269, 1, 270, 1, 270, 1, 270, 1, 270, 1, 270, 1, 270, 1, 270, 1, 271, 1, 271, 1, 271, 1, 271, 1, 271, 1, 271, 1, 271, 1, 271, 1, 272, 1, 272, 1, 272, 1, 272, 1, 272, 1, 272, 1, 272, 1, 272, 1, 273, 1, 273, 1, 273, 1, 273, 1, 273, 1, 274, 1, 274, 1, 274, 1, 274, 1, 274, 1, 275, 1, 275, 1, 275, 1, 275, 1, 275, 1, 275, 1, 275, 1, 276, 1, 276, 1, 276, 1, 276, 1, 276, 1, 276, 1, 276, 1, 276, 1, 276, 1, 276, 1, 277, 1, 277, 1, 277, 1, 277, 1, 277, 1, 277, 1, 277, 1, 278, 1, 278, 1, 278, 1, 278, 1, 278, 1, 278, 1, 278, 1, 279, 1, 279, 1, 279, 1, 280, 1, 280, 1, 280, 1, 280, 1, 280, 1, 280, 1, 280, 1, 281, 1, 281, 1, 281, 1, 281, 1, 281, 1, 281, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 282, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 283, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 284, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 285, 1, 286, 1, 286, 1, 286, 1, 286, 1, 286, 1, 286, 1, 286, 1, 286, 1, 286, 1, 286, 1, 286, 1, 286, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 287, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 288, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 289, 1, 290, 1, 290, 1, 290, 1, 290, 1, 290, 1, 290, 1, 290, 1, 290, 1, 290, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 291, 1, 292, 1, 292, 1, 292, 1, 292, 1, 292, 1, 292, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 293, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 294, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 295, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 296, 1, 297, 1, 297, 1, 297, 1, 297, 1, 297, 1, 297, 1, 297, 1, 298, 1, 298, 1, 298, 1, 298, 1, 298, 1, 298, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 299, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 300, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 301, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 302, 1, 303, 1, 303, 1, 303, 1, 303, 1, 303, 1, 303, 1, 303, 1, 303, 1, 303, 1, 303, 1, 304, 1, 304, 1, 304, 1, 304, 1, 304, 1, 304, 1, 304, 1, 304, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 305, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 306, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 307, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 308, 1, 309, 1, 309, 1, 309, 1, 309, 1, 309, 1, 309, 1, 309, 1, 309, 1, 309, 1, 310, 1, 310, 1, 310, 1, 310, 1, 310, 1, 310, 1, 310, 1, 310, 1, 310, 1, 310, 1, 310, 1, 310, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 311, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 312, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 313, 1, 314, 1, 314, 1, 314, 1, 314, 1, 314, 1, 314, 1, 314, 1, 314, 1, 315, 1, 315, 1, 315, 1, 315, 1, 315, 1, 316, 1, 316, 1, 316, 1, 316, 1, 316, 1, 316, 1, 316, 1, 316, 1, 316, 1, 316, 1, 316, 1, 316, 1, 317, 1, 317, 1, 317, 1, 317, 1, 317, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 318, 1, 319, 1, 319, 1, 319, 1, 319, 1, 319, 1, 320, 1, 320, 1, 320, 1, 321, 1, 321, 1, 322, 1, 322, 1, 323, 1, 323, 1, 324, 1, 324, 1, 325, 1, 325, 1, 326, 1, 326, 1, 327, 1, 327, 1, 328, 1, 328, 1, 329, 4, 329, 3412, 8, 329, 11, 329, 12, 329, 3413, 1, 330, 4, 330, 3417, 8, 330, 11, 330, 12, 330, 3418, 3, 330, 3421, 8, 330, 1, 330, 1, 330, 4, 330, 3425, 8, 330, 11, 330, 12, 330, 3426, 1, 331, 1, 331, 4, 331, 3431, 8, 331, 11, 331, 12, 331, 3432, 4, 331, 3435, 8, 331, 11, 331, 12, 331, 3436, 1, 332, 1, 332, 5, 332, 3441, 8, 332, 10, 332, 12, 332, 3444, 9, 332, 1, 333, 4, 333, 3447, 8, 333, 11, 333, 12, 333, 3448, 1, 333, 5, 333, 3452, 8, 333, 10, 333, 12, 333, 3455, 9, 333, 1, 333, 1, 333, 1, 334, 3, 334, 3460, 8, 334, 1, 334, 1, 334, 1, 334, 1, 335, 1, 335, 1, 335, 1, 335, 1, 335, 1, 335, 5, 335, 3471, 8, 335, 10, 335, 12, 335, 3474, 9, 335, 1, 335, 1, 335, 1, 336, 1, 336, 1, 336, 1, 336, 1, 336, 1, 336, 5, 336, 3484, 8, 336, 10, 336, 12, 336, 3487, 9, 336, 1, 336, 1, 336, 1, 337, 1, 337, 1, 337, 1, 337, 1, 337, 1, 337, 5, 337, 3497, 8, 337, 10, 337, 12, 337, 3500, 9, 337, 1, 337, 1, 337, 1, 338, 1, 338, 1, 339, 1, 339, 1, 339, 1, 339, 1, 3448, 0, 340, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95, 48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56, 113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64, 129, 65, 131, 66, 133, 67, 135, 68, 137, 69, 139, 70, 141, 71, 143, 72, 145, 73, 147, 74, 149, 75, 151, 76, 153, 77, 155, 78, 157, 79, 159, 80, 161, 81, 163, 82, 165, 83, 167, 84, 169, 85, 171, 86, 173, 87, 175, 88, 177, 89, 179, 90, 181, 91, 183, 92, 185, 93, 187, 94, 189, 95, 191, 96, 193, 97, 195, 98, 197, 99, 199, 100, 201, 101, 203, 102, 205, 103, 207, 104, 209, 105, 211, 106, 213, 107, 215, 108, 217, 109, 219, 110, 221, 111, 223, 112, 225, 113, 227, 114, 229, 115, 231, 116, 233, 117, 235, 118, 237, 119, 239, 120, 241, 121, 243, 122, 245, 123, 247, 124, 249, 125, 251, 126, 253, 127, 255, 128, 257, 129, 259, 130, 261, 131, 263, 132, 265, 133, 267, 134, 269, 135, 271, 136, 273, 137, 275, 138, 277, 139, 279, 140, 281, 141, 283, 142, 285, 143, 287, 144, 289, 145, 291, 146, 293, 147, 295, 148, 297, 149, 299, 150, 301, 151, 303, 152, 305, 153, 307, 154, 309, 155, 311, 156, 313, 157, 315, 158, 317, 159, 319, 160, 321, 161, 323, 162, 325, 163, 327, 164, 329, 165, 331, 166, 333, 167, 335, 168, 337, 169, 339, 170, 341, 171, 343, 172, 345, 173, 347, 174, 349, 175, 351, 176, 353, 177, 355, 178, 357, 179, 359, 180, 361, 181, 363, 182, 365, 183, 367, 184, 369, 185, 371, 186, 373, 187, 375, 188, 377, 189, 379, 190, 381, 191, 383, 192, 385, 193, 387, 194, 389, 195, 391, 196, 393, 197, 395, 198, 397, 199, 399, 200, 401, 201, 403, 202, 405, 203, 407, 204, 409, 205, 411, 206, 413, 207, 415, 208, 417, 209, 419, 210, 421, 211, 423, 212, 425, 213, 427, 214, 429, 215, 431, 216, 433, 217, 435, 218, 437, 219, 439, 220, 441, 221, 443, 222, 445, 223, 447, 224, 449, 225, 451, 226, 453, 227, 455, 228, 457, 229, 459, 230, 461, 231, 463, 232, 465, 233, 467, 234, 469, 235, 471, 236, 473, 237, 475, 238, 477, 239, 479, 240, 481, 241, 483, 242, 485, 243, 487, 244, 489, 245, 491, 246, 493, 247, 495, 248, 497, 249, 499, 250, 501, 251, 503, 252, 505, 253, 507, 254, 509, 255, 511, 256, 513, 257, 515, 258, 517, 259, 519, 260, 521, 261, 523, 262, 525, 263, 527, 264, 529, 265, 531, 266, 533, 267, 535, 268, 537, 269, 539, 270, 541, 271, 543, 272, 545, 273, 547, 274, 549, 275, 551, 276, 553, 277, 555, 278, 557, 279, 559, 280, 561, 281, 563, 282, 565, 283, 567, 284, 569, 285, 571, 286, 573, 287, 575, 288, 577, 289, 579, 290, 581, 291, 583, 292, 585, 293, 587, 294, 589, 295, 591, 296, 593, 297, 595, 298, 597, 299, 599, 300, 601, 301, 603, 302, 605, 303, 607, 304, 609, 305, 611, 306, 613, 307, 615, 308, 617, 309, 619, 310, 621, 311, 623, 312, 625, 313, 627, 314, 629, 315, 631, 316, 633, 317, 635, 318, 637, 319, 639, 320, 641, 321, 643, 322, 645, 323, 647, 324, 649, 325, 651, 326, 653, 327, 655, 328, 657, 329, 659, 330, 661, 331, 663, 0, 665, 0, 667, 0, 669, 332, 671, 333, 673, 334, 675, 335, 677, 0, 679, 336, 1, 0, 35, 3, 0, 9, 10, 13, 13, 32, 32, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, 2, 0, 65, 65, 97, 97, 2, 0, 82, 82, 114, 114, 2, 0, 67, 67, 99, 99, 2, 0, 72, 72, 104, 104, 2, 0, 68, 68, 100, 100, 2, 0, 73, 73, 105, 105, 2, 0, 66, 66, 98, 98, 2, 0, 79, 79, 111, 111, 2, 0, 87, 87, 119, 119, 2, 0, 70, 70, 102, 102, 2, 0, 77, 77, 109, 109, 2, 0, 76, 76, 108, 108, 2, 0, 78, 78, 110, 110, 2, 0, 84, 84, 116, 116, 2, 0, 85, 85, 117, 117, 2, 0, 80, 80, 112, 112, 2, 0, 86, 86, 118, 118, 2, 0, 71, 71, 103, 103, 2, 0, 88, 88, 120, 120, 2, 0, 75, 75, 107, 107, 2, 0, 89, 89, 121, 121, 2, 0, 90, 90, 122, 122, 2, 0, 81, 81, 113, 113, 1, 0, 45, 46, 2, 0, 42, 42, 48, 57, 3, 0, 42, 42, 64, 90, 97, 122, 6, 0, 42, 42, 45, 45, 48, 57, 65, 90, 95, 95, 97, 122, 3, 0, 42, 42, 65, 90, 97, 122, 2, 0, 34, 34, 92, 92, 2, 0, 39, 39, 92, 92, 2, 0, 92, 92, 96, 96, 1, 0, 48, 57, 3524, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0, 0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0, 0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 131, 1, 0, 0, 0, 0, 133, 1, 0, 0, 0, 0, 135, 1, 0, 0, 0, 0, 137, 1, 0, 0, 0, 0, 139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0, 0, 0, 0, 147, 1, 0, 0, 0, 0, 149, 1, 0, 0, 0, 0, 151, 1, 0, 0, 0, 0, 153, 1, 0, 0, 0, 0, 155, 1, 0, 0, 0, 0, 157, 1, 0, 0, 0, 0, 159, 1, 0, 0, 0, 0, 161, 1, 0, 0, 0, 0, 163, 1, 0, 0, 0, 0, 165, 1, 0, 0, 0, 0, 167, 1, 0, 0, 0, 0, 169, 1, 0, 0, 0, 0, 171, 1, 0, 0, 0, 0, 173, 1, 0, 0, 0, 0, 175, 1, 0, 0, 0, 0, 177, 1, 0, 0, 0, 0, 179, 1, 0, 0, 0, 0, 181, 1, 0, 0, 0, 0, 183, 1, 0, 0, 0, 0, 185, 1, 0, 0, 0, 0, 187, 1, 0, 0, 0, 0, 189, 1, 0, 0, 0, 0, 191, 1, 0, 0, 0, 0, 193, 1, 0, 0, 0, 0, 195, 1, 0, 0, 0, 0, 197, 1, 0, 0, 0, 0, 199, 1, 0, 0, 0, 0, 201, 1, 0, 0, 0, 0, 203, 1, 0, 0, 0, 0, 205, 1, 0, 0, 0, 0, 207, 1, 0, 0, 0, 0, 209, 1, 0, 0, 0, 0, 211, 1, 0, 0, 0, 0, 213, 1, 0, 0, 0, 0, 215, 1, 0, 0, 0, 0, 217, 1, 0, 0, 0, 0, 219, 1, 0, 0, 0, 0, 221, 1, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 225, 1, 0, 0, 0, 0, 227, 1, 0, 0, 0, 0, 229, 1, 0, 0, 0, 0, 231, 1, 0, 0, 0, 0, 233, 1, 0, 0, 0, 0, 235, 1, 0, 0, 0, 0, 237, 1, 0, 0, 0, 0, 239, 1, 0, 0, 0, 0, 241, 1, 0, 0, 0, 0, 243, 1, 0, 0, 0, 0, 245, 1, 0, 0, 0, 0, 247, 1, 0, 0, 0, 0, 249, 1, 0, 0, 0, 0, 251, 1, 0, 0, 0, 0, 253, 1, 0, 0, 0, 0, 255, 1, 0, 0, 0, 0, 257, 1, 0, 0, 0, 0, 259, 1, 0, 0, 0, 0, 261, 1, 0, 0, 0, 0, 263, 1, 0, 0, 0, 0, 265, 1, 0, 0, 0, 0, 267, 1, 0, 0, 0, 0, 269, 1, 0, 0, 0, 0, 271, 1, 0, 0, 0, 0, 273, 1, 0, 0, 0, 0, 275, 1, 0, 0, 0, 0, 277, 1, 0, 0, 0, 0, 279, 1, 0, 0, 0, 0, 281, 1, 0, 0, 0, 0, 283, 1, 0, 0, 0, 0, 285, 1, 0, 0, 0, 0, 287, 1, 0, 0, 0, 0, 289, 1, 0, 0, 0, 0, 291, 1, 0, 0, 0, 0, 293, 1, 0, 0, 0, 0, 295, 1, 0, 0, 0, 0, 297, 1, 0, 0, 0, 0, 299, 1, 0, 0, 0, 0, 301, 1, 0, 0, 0, 0, 303, 1, 0, 0, 0, 0, 305, 1, 0, 0, 0, 0, 307, 1, 0, 0, 0, 0, 309, 1, 0, 0, 0, 0, 311, 1, 0, 0, 0, 0, 313, 1, 0, 0, 0, 0, 315, 1, 0, 0, 0, 0, 317, 1, 0, 0, 0, 0, 319, 1, 0, 0, 0, 0, 321, 1, 0, 0, 0, 0, 323, 1, 0, 0, 0, 0, 325, 1, 0, 0, 0, 0, 327, 1, 0, 0, 0, 0, 329, 1, 0, 0, 0, 0, 331, 1, 0, 0, 0, 0, 333, 1, 0, 0, 0, 0, 335, 1, 0, 0, 0, 0, 337, 1, 0, 0, 0, 0, 339, 1, 0, 0, 0, 0, 341, 1, 0, 0, 0, 0, 343, 1, 0, 0, 0, 0, 345, 1, 0, 0, 0, 0, 347, 1, 0, 0, 0, 0, 349, 1, 0, 0, 0, 0, 351, 1, 0, 0, 0, 0, 353, 1, 0, 0, 0, 0, 355, 1, 0, 0, 0, 0, 357, 1, 0, 0, 0, 0, 359, 1, 0, 0, 0, 0, 361, 1, 0, 0, 0, 0, 363, 1, 0, 0, 0, 0, 365, 1, 0, 0, 0, 0, 367, 1, 0, 0, 0, 0, 369, 1, 0, 0, 0, 0, 371, 1, 0, 0, 0, 0, 373, 1, 0, 0, 0, 0, 375, 1, 0, 0, 0, 0, 377, 1, 0, 0, 0, 0, 379, 1, 0, 0, 0, 0, 381, 1, 0, 0, 0, 0, 383, 1, 0, 0, 0, 0, 385, 1, 0, 0, 0, 0, 387, 1, 0, 0, 0, 0, 389, 1, 0, 0, 0, 0, 391, 1, 0, 0, 0, 0, 393, 1, 0, 0, 0, 0, 395, 1, 0, 0, 0, 0, 397, 1, 0, 0, 0, 0, 399, 1, 0, 0, 0, 0, 401, 1, 0, 0, 0, 0, 403, 1, 0, 0, 0, 0, 405, 1, 0, 0, 0, 0, 407, 1, 0, 0, 0, 0, 409, 1, 0, 0, 0, 0, 411, 1, 0, 0, 0, 0, 413, 1, 0, 0, 0, 0, 415, 1, 0, 0, 0, 0, 417, 1, 0, 0, 0, 0, 419, 1, 0, 0, 0, 0, 421, 1, 0, 0, 0, 0, 423, 1, 0, 0, 0, 0, 425, 1, 0, 0, 0, 0, 427, 1, 0, 0, 0, 0, 429, 1, 0, 0, 0, 0, 431, 1, 0, 0, 0, 0, 433, 1, 0, 0, 0, 0, 435, 1, 0, 0, 0, 0, 437, 1, 0, 0, 0, 0, 439, 1, 0, 0, 0, 0, 441, 1, 0, 0, 0, 0, 443, 1, 0, 0, 0, 0, 445, 1, 0, 0, 0, 0, 447, 1, 0, 0, 0, 0, 449, 1, 0, 0, 0, 0, 451, 1, 0, 0, 0, 0, 453, 1, 0, 0, 0, 0, 455, 1, 0, 0, 0, 0, 457, 1, 0, 0, 0, 0, 459, 1, 0, 0, 0, 0, 461, 1, 0, 0, 0, 0, 463, 1, 0, 0, 0, 0, 465, 1, 0, 0, 0, 0, 467, 1, 0, 0, 0, 0, 469, 1, 0, 0, 0, 0, 471, 1, 0, 0, 0, 0, 473, 1, 0, 0, 0, 0, 475, 1, 0, 0, 0, 0, 477, 1, 0, 0, 0, 0, 479, 1, 0, 0, 0, 0, 481, 1, 0, 0, 0, 0, 483, 1, 0, 0, 0, 0, 485, 1, 0, 0, 0, 0, 487, 1, 0, 0, 0, 0, 489, 1, 0, 0, 0, 0, 491, 1, 0, 0, 0, 0, 493, 1, 0, 0, 0, 0, 495, 1, 0, 0, 0, 0, 497, 1, 0, 0, 0, 0, 499, 1, 0, 0, 0, 0, 501, 1, 0, 0, 0, 0, 503, 1, 0, 0, 0, 0, 505, 1, 0, 0, 0, 0, 507, 1, 0, 0, 0, 0, 509, 1, 0, 0, 0, 0, 511, 1, 0, 0, 0, 0, 513, 1, 0, 0, 0, 0, 515, 1, 0, 0, 0, 0, 517, 1, 0, 0, 0, 0, 519, 1, 0, 0, 0, 0, 521, 1, 0, 0, 0, 0, 523, 1, 0, 0, 0, 0, 525, 1, 0, 0, 0, 0, 527, 1, 0, 0, 0, 0, 529, 1, 0, 0, 0, 0, 531, 1, 0, 0, 0, 0, 533, 1, 0, 0, 0, 0, 535, 1, 0, 0, 0, 0, 537, 1, 0, 0, 0, 0, 539, 1, 0, 0, 0, 0, 541, 1, 0, 0, 0, 0, 543, 1, 0, 0, 0, 0, 545, 1, 0, 0, 0, 0, 547, 1, 0, 0, 0, 0, 549, 1, 0, 0, 0, 0, 551, 1, 0, 0, 0, 0, 553, 1, 0, 0, 0, 0, 555, 1, 0, 0, 0, 0, 557, 1, 0, 0, 0, 0, 559, 1, 0, 0, 0, 0, 561, 1, 0, 0, 0, 0, 563, 1, 0, 0, 0, 0, 565, 1, 0, 0, 0, 0, 567, 1, 0, 0, 0, 0, 569, 1, 0, 0, 0, 0, 571, 1, 0, 0, 0, 0, 573, 1, 0, 0, 0, 0, 575, 1, 0, 0, 0, 0, 577, 1, 0, 0, 0, 0, 579, 1, 0, 0, 0, 0, 581, 1, 0, 0, 0, 0, 583, 1, 0, 0, 0, 0, 585, 1, 0, 0, 0, 0, 587, 1, 0, 0, 0, 0, 589, 1, 0, 0, 0, 0, 591, 1, 0, 0, 0, 0, 593, 1, 0, 0, 0, 0, 595, 1, 0, 0, 0, 0, 597, 1, 0, 0, 0, 0, 599, 1, 0, 0, 0, 0, 601, 1, 0, 0, 0, 0, 603, 1, 0, 0, 0, 0, 605, 1, 0, 0, 0, 0, 607, 1, 0, 0, 0, 0, 609, 1, 0, 0, 0, 0, 611, 1, 0, 0, 0, 0, 613, 1, 0, 0, 0, 0, 615, 1, 0, 0, 0, 0, 617, 1, 0, 0, 0, 0, 619, 1, 0, 0, 0, 0, 621, 1, 0, 0, 0, 0, 623, 1, 0, 0, 0, 0, 625, 1, 0, 0, 0, 0, 627, 1, 0, 0, 0, 0, 629, 1, 0, 0, 0, 0, 631, 1, 0, 0, 0, 0, 633, 1, 0, 0, 0, 0, 635, 1, 0, 0, 0, 0, 637, 1, 0, 0, 0, 0, 639, 1, 0, 0, 0, 0, 641, 1, 0, 0, 0, 0, 643, 1, 0, 0, 0, 0, 645, 1, 0, 0, 0, 0, 647, 1, 0, 0, 0, 0, 649, 1, 0, 0, 0, 0, 651, 1, 0, 0, 0, 0, 653, 1, 0, 0, 0, 0, 655, 1, 0, 0, 0, 0, 657, 1, 0, 0, 0, 0, 659, 1, 0, 0, 0, 0, 661, 1, 0, 0, 0, 0, 669, 1, 0, 0, 0, 0, 671, 1, 0, 0, 0, 0, 673, 1, 0, 0, 0, 0, 675, 1, 0, 0, 0, 0, 679, 1, 0, 0, 0, 1, 682, 1, 0, 0, 0, 3, 688, 1, 0, 0, 0, 5, 695, 1, 0, 0, 0, 7, 704, 1, 0, 0, 0, 9, 709, 1, 0, 0, 0, 11, 714, 1, 0, 0, 0, 13, 720, 1, 0, 0, 0, 15, 727, 1, 0, 0, 0, 17, 734, 1, 0, 0, 0, 19, 740, 1, 0, 0, 0, 21, 746, 1, 0, 0, 0, 23, 751, 1, 0, 0, 0, 25, 756, 1, 0, 0, 0, 27, 761, 1, 0, 0, 0, 29, 765, 1, 0, 0, 0, 31, 770, 1, 0, 0, 0, 33, 776, 1, 0, 0, 0, 35, 783, 1, 0, 0, 0, 37, 789, 1, 0, 0, 0, 39, 795, 1, 0, 0, 0, 41, 800, 1, 0, 0, 0, 43, 808, 1, 0, 0, 0, 45, 817, 1, 0, 0, 0, 47, 827, 1, 0, 0, 0, 49, 834, 1, 0, 0, 0, 51, 837, 1, 0, 0, 0, 53, 840, 1, 0, 0, 0, 55, 843, 1, 0, 0, 0, 57, 846, 1, 0, 0, 0, 59, 853, 1, 0, 0, 0, 61, 859, 1, 0, 0, 0, 63, 861, 1, 0, 0, 0, 65, 866, 1, 0, 0, 0, 67, 878, 1, 0, 0, 0, 69, 885, 1, 0, 0, 0, 71, 890, 1, 0, 0, 0, 73, 894, 1, 0, 0, 0, 75, 897, 1, 0, 0, 0, 77, 901, 1, 0, 0, 0, 79, 911, 1, 0, 0, 0, 81, 923, 1, 0, 0, 0, 83, 941, 1, 0, 0, 0, 85, 952, 1, 0, 0, 0, 87, 959, 1, 0, 0, 0, 89, 965, 1, 0, 0, 0, 91, 975, 1, 0, 0, 0, 93, 986, 1, 0, 0, 0, 95, 1000, 1, 0, 0, 0, 97, 1016, 1, 0, 0, 0, 99, 1029, 1, 0, 0, 0, 101, 1041, 1, 0, 0, 0, 103, 1054, 1, 0, 0, 0, 105, 1065, 1, 0, 0, 0, 107, 1078, 1, 0, 0, 0, 109, 1093, 1, 0, 0, 0, 111, 1104, 1, 0, 0, 0, 113, 1114, 1, 0, 0, 0, 115, 1133, 1, 0, 0, 0, 117, 1157, 1, 0, 0, 0, 119, 1162, 1, 0, 0, 0, 121, 1165, 1, 0, 0, 0, 123, 1169, 1, 0, 0, 0, 125, 1172, 1, 0, 0, 0, 127, 1176, 1, 0, 0, 0, 129, 1180, 1, 0, 0, 0, 131, 1185, 1, 0, 0, 0, 133, 1191, 1, 0, 0, 0, 135, 1198, 1, 0, 0, 0, 137, 1209, 1, 0, 0, 0, 139, 1218, 1, 0, 0, 0, 141, 1222, 1, 0, 0, 0, 143, 1231, 1, 0, 0, 0, 145, 1247, 1, 0, 0, 0, 147, 1258, 1, 0, 0, 0, 149, 1270, 1, 0, 0, 0, 151, 1281, 1, 0, 0, 0, 153, 1286, 1, 0, 0, 0, 155, 1303, 1, 0, 0, 0, 157, 1315, 1, 0, 0, 0, 159, 1327, 1, 0, 0, 0, 161, 1339, 1, 0, 0, 0, 163, 1348, 1, 0, 0, 0, 165, 1360, 1, 0, 0, 0, 167, 1372, 1, 0, 0, 0, 169, 1379, 1, 0, 0, 0, 171, 1398, 1, 0, 0, 0, 173, 1412, 1, 0, 0, 0, 175, 1427, 1, 0, 0, 0, 177, 1441, 1, 0, 0, 0, 179, 1447, 1, 0, 0, 0, 181, 1461, 1, 0, 0, 0, 183, 1469, 1, 0, 0, 0, 185, 1476, 1, 0, 0, 0, 187, 1495, 1, 0, 0, 0, 189, 1512, 1, 0, 0, 0, 191, 1517, 1, 0, 0, 0, 193, 1530, 1, 0, 0, 0, 195, 1535, 1, 0, 0, 0, 197, 1546, 1, 0, 0, 0, 199, 1556, 1, 0, 0, 0, 201, 1563, 1, 0, 0, 0, 203, 1575, 1, 0, 0, 0, 205, 1579, 1, 0, 0, 0, 207, 1587, 1, 0, 0, 0, 209, 1594, 1, 0, 0, 0, 211, 1599, 1, 0, 0, 0, 213, 1605, 1, 0, 0, 0, 215, 1612, 1, 0, 0, 0, 217, 1620, 1, 0, 0, 0, 219, 1622, 1, 0, 0, 0, 221, 1624, 1, 0, 0, 0, 223, 1626, 1, 0, 0, 0, 225, 1628, 1, 0, 0, 0, 227, 1630, 1, 0, 0, 0, 229, 1632, 1, 0, 0, 0, 231, 1635, 1, 0, 0, 0, 233, 1638, 1, 0, 0, 0, 235, 1641, 1, 0, 0, 0, 237, 1643, 1, 0, 0, 0, 239, 1645, 1, 0, 0, 0, 241, 1647, 1, 0, 0, 0, 243, 1649, 1, 0, 0, 0, 245, 1651, 1, 0, 0, 0, 247, 1653, 1, 0, 0, 0, 249, 1655, 1, 0, 0, 0, 251, 1657, 1, 0, 0, 0, 253, 1659, 1, 0, 0, 0, 255, 1661, 1, 0, 0, 0, 257, 1663, 1, 0, 0, 0, 259, 1665, 1, 0, 0, 0, 261, 1667, 1, 0, 0, 0, 263, 1669, 1, 0, 0, 0, 265, 1671, 1, 0, 0, 0, 267, 1673, 1, 0, 0, 0, 269, 1675, 1, 0, 0, 0, 271, 1679, 1, 0, 0, 0, 273, 1685, 1, 0, 0, 0, 275, 1700, 1, 0, 0, 0, 277, 1706, 1, 0, 0, 0, 279, 1718, 1, 0, 0, 0, 281, 1722, 1, 0, 0, 0, 283, 1727, 1, 0, 0, 0, 285, 1734, 1, 0, 0, 0, 287, 1738, 1, 0, 0, 0, 289, 1743, 1, 0, 0, 0, 291, 1749, 1, 0, 0, 0, 293, 1755, 1, 0, 0, 0, 295, 1762, 1, 0, 0, 0, 297, 1766, 1, 0, 0, 0, 299, 1772, 1, 0, 0, 0, 301, 1781, 1, 0, 0, 0, 303, 1789, 1, 0, 0, 0, 305, 1801, 1, 0, 0, 0, 307, 1812, 1, 0, 0, 0, 309, 1823, 1, 0, 0, 0, 311, 1828, 1, 0, 0, 0, 313, 1834, 1, 0, 0, 0, 315, 1839, 1, 0, 0, 0, 317, 1844, 1, 0, 0, 0, 319, 1851, 1, 0, 0, 0, 321, 1860, 1, 0, 0, 0, 323, 1874, 1, 0, 0, 0, 325, 1881, 1, 0, 0, 0, 327, 1893, 1, 0, 0, 0, 329, 1901, 1, 0, 0, 0, 331, 1910, 1, 0, 0, 0, 333, 1921, 1, 0, 0, 0, 335, 1932, 1, 0, 0, 0, 337, 1937, 1, 0, 0, 0, 339, 1947, 1, 0, 0, 0, 341, 1949, 1, 0, 0, 0, 343, 1952, 1, 0, 0, 0, 345, 1956, 1, 0, 0, 0, 347, 1961, 1, 0, 0, 0, 349, 1966, 1, 0, 0, 0, 351, 1974, 1, 0, 0, 0, 353, 1979, 1, 0, 0, 0, 355, 1985, 1, 0, 0, 0, 357, 1987, 1, 0, 0, 0, 359, 1991, 1, 0, 0, 0, 361, 1997, 1, 0, 0, 0, 363, 2000, 1, 0, 0, 0, 365, 2004, 1, 0, 0, 0, 367, 2010, 1, 0, 0, 0, 369, 2015, 1, 0, 0, 0, 371, 2019, 1, 0, 0, 0, 373, 2022, 1, 0, 0, 0, 375, 2031, 1, 0, 0, 0, 377, 2035, 1, 0, 0, 0, 379, 2041, 1, 0, 0, 0, 381, 2046, 1, 0, 0, 0, 383, 2052, 1, 0, 0, 0, 385, 2057, 1, 0, 0, 0, 387, 2062, 1, 0, 0, 0, 389, 2071, 1, 0, 0, 0, 391, 2076, 1, 0, 0, 0, 393, 2081, 1, 0, 0, 0, 395, 2086, 1, 0, 0, 0, 397, 2092, 1, 0, 0, 0, 399, 2096, 1, 0, 0, 0, 401, 2100, 1, 0, 0, 0, 403, 2108, 1, 0, 0, 0, 405, 2116, 1, 0, 0, 0, 407, 2120, 1, 0, 0, 0, 409, 2124, 1, 0, 0, 0, 411, 2132, 1, 0, 0, 0, 413, 2140, 1, 0, 0, 0, 415, 2148, 1, 0, 0, 0, 417, 2161, 1, 0, 0, 0, 419, 2174, 1, 0, 0, 0, 421, 2192, 1, 0, 0, 0, 423, 2200, 1, 0, 0, 0, 425, 2205, 1, 0, 0, 0, 427, 2214, 1, 0, 0, 0, 429, 2223, 1, 0, 0, 0, 431, 2235, 1, 0, 0, 0, 433, 2244, 1, 0, 0, 0, 435, 2252, 1, 0, 0, 0, 437, 2263, 1, 0, 0, 0, 439, 2273, 1, 0, 0, 0, 441, 2283, 1, 0, 0, 0, 443, 2296, 1, 0, 0, 0, 445, 2308, 1, 0, 0, 0, 447, 2316, 1, 0, 0, 0, 449, 2326, 1, 0, 0, 0, 451, 2340, 1, 0, 0, 0, 453, 2351, 1, 0, 0, 0, 455, 2360, 1, 0, 0, 0, 457, 2370, 1, 0, 0, 0, 459, 2385, 1, 0, 0, 0, 461, 2394, 1, 0, 0, 0, 463, 2403, 1, 0, 0, 0, 465, 2413, 1, 0, 0, 0, 467, 2417, 1, 0, 0, 0, 469, 2428, 1, 0, 0, 0, 471, 2440, 1, 0, 0, 0, 473, 2452, 1, 0, 0, 0, 475, 2464, 1, 0, 0, 0, 477, 2472, 1, 0, 0, 0, 479, 2480, 1, 0, 0, 0, 481, 2488, 1, 0, 0, 0, 483, 2493, 1, 0, 0, 0, 485, 2502, 1, 0, 0, 0, 487, 2512, 1, 0, 0, 0, 489, 2525, 1, 0, 0, 0, 491, 2539, 1, 0, 0, 0, 493, 2551, 1, 0, 0, 0, 495, 2563, 1, 0, 0, 0, 497, 2571, 1, 0, 0, 0, 499, 2582, 1, 0, 0, 0, 501, 2597, 1, 0, 0, 0, 503, 2606, 1, 0, 0, 0, 505, 2615, 1, 0, 0, 0, 507, 2629, 1, 0, 0, 0, 509, 2637, 1, 0, 0, 0, 511, 2646, 1, 0, 0, 0, 513, 2653, 1, 0, 0, 0, 515, 2663, 1, 0, 0, 0, 517, 2669, 1, 0, 0, 0, 519, 2675, 1, 0, 0, 0, 521, 2680, 1, 0, 0, 0, 523, 2683, 1, 0, 0, 0, 525, 2689, 1, 0, 0, 0, 527, 2695, 1, 0, 0, 0, 529, 2702, 1, 0, 0, 0, 531, 2712, 1, 0, 0, 0, 533, 2719, 1, 0, 0, 0, 535, 2726, 1, 0, 0, 0, 537, 2732, 1, 0, 0, 0, 539, 2737, 1, 0, 0, 0, 541, 2743, 1, 0, 0, 0, 543, 2750, 1, 0, 0, 0, 545, 2758, 1, 0, 0, 0, 547, 2766, 1, 0, 0, 0, 549, 2771, 1, 0, 0, 0, 551, 2776, 1, 0, 0, 0, 553, 2783, 1, 0, 0, 0, 555, 2793, 1, 0, 0, 0, 557, 2800, 1, 0, 0, 0, 559, 2807, 1, 0, 0, 0, 561, 2810, 1, 0, 0, 0, 563, 2817, 1, 0, 0, 0, 565, 2823, 1, 0, 0, 0, 567, 2836, 1, 0, 0, 0, 569, 2856, 1, 0, 0, 0, 571, 2874, 1, 0, 0, 0, 573, 2894, 1, 0, 0, 0, 575, 2906, 1, 0, 0, 0, 577, 2919, 1, 0, 0, 0, 579, 2942, 1, 0, 0, 0, 581, 2959, 1, 0, 0, 0, 583, 2968, 1, 0, 0, 0, 585, 3004, 1, 0, 0, 0, 587, 3010, 1, 0, 0, 0, 589, 3027, 1, 0, 0, 0, 591, 3041, 1, 0, 0, 0, 593, 3058, 1, 0, 0, 0, 595, 3085, 1, 0, 0, 0, 597, 3092, 1, 0, 0, 0, 599, 3098, 1, 0, 0, 0, 601, 3119, 1, 0, 0, 0, 603, 3139, 1, 0, 0, 0, 605, 3160, 1, 0, 0, 0, 607, 3174, 1, 0, 0, 0, 609, 3184, 1, 0, 0, 0, 611, 3192, 1, 0, 0, 0, 613, 3210, 1, 0, 0, 0, 615, 3234, 1, 0, 0, 0, 617, 3249, 1, 0, 0, 0, 619, 3270, 1, 0, 0, 0, 621, 3279, 1, 0, 0, 0, 623, 3291, 1, 0, 0, 0, 625, 3305, 1, 0, 0, 0, 627, 3320, 1, 0, 0, 0, 629, 3339, 1, 0, 0, 0, 631, 3347, 1, 0, 0, 0, 633, 3352, 1, 0, 0, 0, 635, 3364, 1, 0, 0, 0, 637, 3369, 1, 0, 0, 0, 639, 3386, 1, 0, 0, 0, 641, 3391, 1, 0, 0, 0, 643, 3394, 1, 0, 0, 0, 645, 3396, 1, 0, 0, 0, 647, 3398, 1, 0, 0, 0, 649, 3400, 1, 0, 0, 0, 651, 3402, 1, 0, 0, 0, 653, 3404, 1, 0, 0, 0, 655, 3406, 1, 0, 0, 0, 657, 3408, 1, 0, 0, 0, 659, 3411, 1, 0, 0, 0, 661, 3420, 1, 0, 0, 0, 663, 3434, 1, 0, 0, 0, 665, 3438, 1, 0, 0, 0, 667, 3446, 1, 0, 0, 0, 669, 3459, 1, 0, 0, 0, 671, 3464, 1, 0, 0, 0, 673, 3477, 1, 0, 0, 0, 675, 3490, 1, 0, 0, 0, 677, 3503, 1, 0, 0, 0, 679, 3505, 1, 0, 0, 0, 681, 683, 7, 0, 0, 0, 682, 681, 1, 0, 0, 0, 683, 684, 1, 0, 0, 0, 684, 682, 1, 0, 0, 0, 684, 685, 1, 0, 0, 0, 685, 686, 1, 0, 0, 0, 686, 687, 6, 0, 0, 0, 687, 2, 1, 0, 0, 0, 688, 689, 7, 1, 0, 0, 689, 690, 7, 2, 0, 0, 690, 691, 7, 3, 0, 0, 691, 692, 7, 4, 0, 0, 692, 693, 7, 5, 0, 0, 693, 694, 7, 6, 0, 0, 694, 4, 1, 0, 0, 0, 695, 696, 7, 7, 0, 0, 696, 697, 7, 2, 0, 0, 697, 698, 7, 1, 0, 0, 698, 699, 7, 5, 0, 0, 699, 700, 7, 4, 0, 0, 700, 701, 7, 8, 0, 0, 701, 702, 7, 9, 0, 0, 702, 703, 7, 2, 0, 0, 703, 6, 1, 0, 0, 0, 704, 705, 7, 1, 0, 0, 705, 706, 7, 6, 0, 0, 706, 707, 7, 10, 0, 0, 707, 708, 7, 11, 0, 0, 708, 8, 1, 0, 0, 0, 709, 710, 7, 12, 0, 0, 710, 711, 7, 4, 0, 0, 711, 712, 7, 10, 0, 0, 712, 713, 7, 13, 0, 0, 713, 10, 1, 0, 0, 0, 714, 715, 7, 11, 0, 0, 715, 716, 7, 6, 0, 0, 716, 717, 7, 2, 0, 0, 717, 718, 7, 4, 0, 0, 718, 719, 7, 2, 0, 0, 719, 12, 1, 0, 0, 0, 720, 721, 7, 12, 0, 0, 721, 722, 7, 8, 0, 0, 722, 723, 7, 2, 0, 0, 723, 724, 7, 14, 0, 0, 724, 725, 7, 7, 0, 0, 725, 726, 7, 1, 0, 0, 726, 14, 1, 0, 0, 0, 727, 728, 7, 4, 0, 0, 728, 729, 7, 2, 0, 0, 729, 730, 7, 15, 0, 0, 730, 731, 7, 3, 0, 0, 731, 732, 7, 13, 0, 0, 732, 733, 7, 2, 0, 0, 733, 16, 1, 0, 0, 0, 734, 735, 7, 1, 0, 0, 735, 736, 7, 16, 0, 0, 736, 737, 7, 3, 0, 0, 737, 738, 7, 16, 0, 0, 738, 739, 7, 1, 0, 0, 739, 18, 1, 0, 0, 0, 740, 741, 7, 7, 0, 0, 741, 742, 7, 2, 0, 0, 742, 743, 7, 7, 0, 0, 743, 744, 7, 17, 0, 0, 744, 745, 7, 18, 0, 0, 745, 20, 1, 0, 0, 0, 746, 747, 7, 1, 0, 0, 747, 748, 7, 10, 0, 0, 748, 749, 7, 4, 0, 0, 749, 750, 7, 16, 0, 0, 750, 22, 1, 0, 0, 0, 751, 752, 7, 2, 0, 0, 752, 753, 7, 19, 0, 0, 753, 754, 7, 3, 0, 0, 754, 755, 7, 14, 0, 0, 755, 24, 1, 0, 0, 0, 756, 757, 7, 6, 0, 0, 757, 758, 7, 2, 0, 0, 758, 759, 7, 3, 0, 0, 759, 760, 7, 7, 0, 0, 760, 26, 1, 0, 0, 0, 761, 762, 7, 16, 0, 0, 762, 763, 7, 10, 0, 0, 763, 764, 7, 18, 0, 0, 764, 28, 1, 0, 0, 0, 765, 766, 7, 4, 0, 0, 766, 767, 7, 3, 0, 0, 767, 768, 7, 4, 0, 0, 768, 769, 7, 2, 0, 0, 769, 30, 1, 0, 0, 0, 770, 771, 7, 18, 0, 0, 771, 772, 7, 3, 0, 0, 772, 773, 7, 4, 0, 0, 773, 774, 7, 1, 0, 0, 774, 775, 7, 2, 0, 0, 775, 32, 1, 0, 0, 0, 776, 777, 7, 13, 0, 0, 777, 778, 7, 2, 0, 0, 778, 779, 7, 16, 0, 0, 779, 780, 7, 6, 0, 0, 780, 781, 7, 10, 0, 0, 781, 782, 7, 7, 0, 0, 782, 34, 1, 0, 0, 0, 783, 784, 7, 4, 0, 0, 784, 785, 7, 2, 0, 0, 785, 786, 7, 20, 0, 0, 786, 787, 7, 2, 0, 0, 787, 788, 7, 21, 0, 0, 788, 36, 1, 0, 0, 0, 789, 790, 7, 18, 0, 0, 790, 791, 7, 17, 0, 0, 791, 792, 7, 15, 0, 0, 792, 793, 7, 5, 0, 0, 793, 794, 7, 16, 0, 0, 794, 38, 1, 0, 0, 0, 795, 796, 7, 20, 0, 0, 796, 797, 7, 4, 0, 0, 797, 798, 7, 10, 0, 0, 798, 799, 7, 22, 0, 0, 799, 40, 1, 0, 0, 0, 800, 801, 7, 18, 0, 0, 801, 802, 7, 3, 0, 0, 802, 803, 7, 16, 0, 0, 803, 804, 7, 16, 0, 0, 804, 805, 7, 2, 0, 0, 805, 806, 7, 4, 0, 0, 806, 807, 7, 15, 0, 0, 807, 42, 1, 0, 0, 0, 808, 809, 7, 18, 0, 0, 809, 810, 7, 3, 0, 0, 810, 811, 7, 16, 0, 0, 811, 812, 7, 16, 0, 0, 812, 813, 7, 2, 0, 0, 813, 814, 7, 4, 0, 0, 814, 815, 7, 15, 0, 0, 815, 816, 7, 1, 0, 0, 816, 44, 1, 0, 0, 0, 817, 818, 7, 15, 0, 0, 818, 819, 7, 2, 0, 0, 819, 820, 7, 11, 0, 0, 820, 821, 5, 95, 0, 0, 821, 822, 7, 12, 0, 0, 822, 823, 7, 8, 0, 0, 823, 824, 7, 2, 0, 0, 824, 825, 7, 14, 0, 0, 825, 826, 7, 7, 0, 0, 826, 46, 1, 0, 0, 0, 827, 828, 7, 22, 0, 0, 828, 829, 7, 13, 0, 0, 829, 830, 7, 2, 0, 0, 830, 831, 7, 3, 0, 0, 831, 832, 7, 15, 0, 0, 832, 833, 7, 1, 0, 0, 833, 48, 1, 0, 0, 0, 834, 835, 7, 3, 0, 0, 835, 836, 7, 7, 0, 0, 836, 50, 1, 0, 0, 0, 837, 838, 7, 13, 0, 0, 838, 839, 7, 14, 0, 0, 839, 52, 1, 0, 0, 0, 840, 841, 7, 3, 0, 0, 841, 842, 7, 1, 0, 0, 842, 54, 1, 0, 0, 0, 843, 844, 7, 9, 0, 0, 844, 845, 7, 23, 0, 0, 845, 56, 1, 0, 0, 0, 846, 847, 7, 1, 0, 0, 847, 848, 7, 10, 0, 0, 848, 849, 7, 17, 0, 0, 849, 850, 7, 4, 0, 0, 850, 851, 7, 5, 0, 0, 851, 852, 7, 2, 0, 0, 852, 58, 1, 0, 0, 0, 853, 854, 7, 8, 0, 0, 854, 855, 7, 15, 0, 0, 855, 856, 7, 7, 0, 0, 856, 857, 7, 2, 0, 0, 857, 858, 7, 21, 0, 0, 858, 60, 1, 0, 0, 0, 859, 860, 7, 7, 0, 0, 860, 62, 1, 0, 0, 0, 861, 862, 7, 7, 0, 0, 862, 863, 7, 2, 0, 0, 863, 864, 7, 1, 0, 0, 864, 865, 7, 5, 0, 0, 865, 64, 1, 0, 0, 0, 866, 867, 7, 7, 0, 0, 867, 868, 7, 3, 0, 0, 868, 869, 7, 16, 0, 0, 869, 870, 7, 3, 0, 0, 870, 871, 7, 1, 0, 0, 871, 872, 7, 10, 0, 0, 872, 873, 7, 17, 0, 0, 873, 874, 7, 4, 0, 0, 874, 875, 7, 5, 0, 0, 875, 876, 7, 2, 0, 0, 876, 877, 7, 1, 0, 0, 877, 66, 1, 0, 0, 0, 878, 879, 7, 1, 0, 0, 879, 880, 7, 10, 0, 0, 880, 881, 7, 4, 0, 0, 881, 882, 7, 16, 0, 0, 882, 883, 7, 9, 0, 0, 883, 884, 7, 23, 0, 0, 884, 68, 1, 0, 0, 0, 885, 886, 7, 3, 0, 0, 886, 887, 7, 17, 0, 0, 887, 888, 7, 16, 0, 0, 888, 889, 7, 10, 0, 0, 889, 70, 1, 0, 0, 0, 890, 891, 7, 1, 0, 0, 891, 892, 7, 16, 0, 0, 892, 893, 7, 4, 0, 0, 893, 72, 1, 0, 0, 0, 894, 895, 7, 8, 0, 0, 895, 896, 7, 18, 0, 0, 896, 74, 1, 0, 0, 0, 897, 898, 7, 15, 0, 0, 898, 899, 7, 17, 0, 0, 899, 900, 7, 13, 0, 0, 900, 76, 1, 0, 0, 0, 901, 902, 7, 22, 0, 0, 902, 903, 7, 2, 0, 0, 903, 904, 7, 2, 0, 0, 904, 905, 7, 18, 0, 0, 905, 906, 7, 2, 0, 0, 906, 907, 7, 13, 0, 0, 907, 908, 7, 18, 0, 0, 908, 909, 7, 16, 0, 0, 909, 910, 7, 23, 0, 0, 910, 78, 1, 0, 0, 0, 911, 912, 7, 5, 0, 0, 912, 913, 7, 10, 0, 0, 913, 914, 7, 15, 0, 0, 914, 915, 7, 1, 0, 0, 915, 916, 7, 2, 0, 0, 916, 917, 7, 5, 0, 0, 917, 918, 7, 17, 0, 0, 918, 919, 7, 16, 0, 0, 919, 920, 7, 8, 0, 0, 920, 921, 7, 19, 0, 0, 921, 922, 7, 2, 0, 0, 922, 80, 1, 0, 0, 0, 923, 924, 7, 7, 0, 0, 924, 925, 7, 2, 0, 0, 925, 926, 7, 7, 0, 0, 926, 927, 7, 17, 0, 0, 927, 928, 7, 18, 0, 0, 928, 929, 5, 95, 0, 0, 929, 930, 7, 1, 0, 0, 930, 931, 7, 18, 0, 0, 931, 932, 7, 14, 0, 0, 932, 933, 7, 8, 0, 0, 933, 934, 7, 16, 0, 0, 934, 935, 7, 19, 0, 0, 935, 936, 7, 3, 0, 0, 936, 937, 7, 14, 0, 0, 937, 938, 7, 17, 0, 0, 938, 939, 7, 2, 0, 0, 939, 940, 7, 1, 0, 0, 940, 82, 1, 0, 0, 0, 941, 942, 7, 18, 0, 0, 942, 943, 7, 3, 0, 0, 943, 944, 7, 4, 0, 0, 944, 945, 7, 16, 0, 0, 945, 946, 7, 8, 0, 0, 946, 947, 7, 16, 0, 0, 947, 948, 7, 8, 0, 0, 948, 949, 7, 10, 0, 0, 949, 950, 7, 15, 0, 0, 950, 951, 7, 1, 0, 0, 951, 84, 1, 0, 0, 0, 952, 953, 7, 3, 0, 0, 953, 954, 7, 14, 0, 0, 954, 955, 7, 14, 0, 0, 955, 956, 7, 15, 0, 0, 956, 957, 7, 17, 0, 0, 957, 958, 7, 13, 0, 0, 958, 86, 1, 0, 0, 0, 959, 960, 7, 7, 0, 0, 960, 961, 7, 2, 0, 0, 961, 962, 7, 14, 0, 0, 962, 963, 7, 8, 0, 0, 963, 964, 7, 13, 0, 0, 964, 88, 1, 0, 0, 0, 965, 966, 7, 5, 0, 0, 966, 967, 7, 2, 0, 0, 967, 968, 7, 15, 0, 0, 968, 969, 7, 16, 0, 0, 969, 970, 7, 4, 0, 0, 970, 971, 7, 10, 0, 0, 971, 972, 7, 8, 0, 0, 972, 973, 7, 7, 0, 0, 973, 974, 7, 1, 0, 0, 974, 90, 1, 0, 0, 0, 975, 976, 7, 8, 0, 0, 976, 977, 7, 16, 0, 0, 977, 978, 7, 2, 0, 0, 978, 979, 7, 4, 0, 0, 979, 980, 7, 3, 0, 0, 980, 981, 7, 16, 0, 0, 981, 982, 7, 8, 0, 0, 982, 983, 7, 10, 0, 0, 983, 984, 7, 15, 0, 0, 984, 985, 7, 1, 0, 0, 985, 92, 1, 0, 0, 0, 986, 987, 7, 7, 0, 0, 987, 988, 7, 8, 0, 0, 988, 989, 7, 1, 0, 0, 989, 990, 7, 16, 0, 0, 990, 991, 7, 3, 0, 0, 991, 992, 7, 15, 0, 0, 992, 993, 7, 5, 0, 0, 993, 994, 7, 2, 0, 0, 994, 995, 5, 95, 0, 0, 995, 996, 7, 16, 0, 0, 996, 997, 7, 23, 0, 0, 997, 998, 7, 18, 0, 0, 998, 999, 7, 2, 0, 0, 999, 94, 1, 0, 0, 0, 1000, 1001, 7, 15, 0, 0, 1001, 1002, 7, 17, 0, 0, 1002, 1003, 7, 13, 0, 0, 1003, 1004, 7, 9, 0, 0, 1004, 1005, 7, 2, 0, 0, 1005, 1006, 7, 4, 0, 0, 1006, 1007, 5, 95, 0, 0, 1007, 1008, 7, 10, 0, 0, 1008, 1009, 7, 12, 0, 0, 1009, 1010, 5, 95, 0, 0, 1010, 1011, 7, 16, 0, 0, 1011, 1012, 7, 4, 0, 0, 1012, 1013, 7, 2, 0, 0, 1013, 1014, 7, 2, 0, 0, 1014, 1015, 7, 1, 0, 0, 1015, 96, 1, 0, 0, 0, 1016, 1017, 7, 1, 0, 0, 1017, 1018, 7, 6, 0, 0, 1018, 1019, 7, 8, 0, 0, 1019, 1020, 7, 15, 0, 0, 1020, 1021, 7, 20, 0, 0, 1021, 1022, 7, 14, 0, 0, 1022, 1023, 7, 2, 0, 0, 1023, 1024, 5, 95, 0, 0, 1024, 1025, 7, 1, 0, 0, 1025, 1026, 7, 8, 0, 0, 1026, 1027, 7, 24, 0, 0, 1027, 1028, 7, 2, 0, 0, 1028, 98, 1, 0, 0, 0, 1029, 1030, 7, 1, 0, 0, 1030, 1031, 7, 3, 0, 0, 1031, 1032, 7, 13, 0, 0, 1032, 1033, 7, 18, 0, 0, 1033, 1034, 7, 14, 0, 0, 1034, 1035, 7, 2, 0, 0, 1035, 1036, 5, 95, 0, 0, 1036, 1037, 7, 1, 0, 0, 1037, 1038, 7, 8, 0, 0, 1038, 1039, 7, 24, 0, 0, 1039, 1040, 7, 2, 0, 0, 1040, 100, 1, 0, 0, 0, 1041, 1042, 7, 10, 0, 0, 1042, 1043, 7, 17, 0, 0, 1043, 1044, 7, 16, 0, 0, 1044, 1045, 7, 18, 0, 0, 1045, 1046, 7, 17, 0, 0, 1046, 1047, 7, 16, 0, 0, 1047, 1048, 5, 95, 0, 0, 1048, 1049, 7, 3, 0, 0, 1049, 1050, 7, 12, 0, 0, 1050, 1051, 7, 16, 0, 0, 1051, 1052, 7, 2, 0, 0, 1052, 1053, 7, 4, 0, 0, 1053, 102, 1, 0, 0, 0, 1054, 1055, 7, 16, 0, 0, 1055, 1056, 7, 8, 0, 0, 1056, 1057, 7, 13, 0, 0, 1057, 1058, 7, 2, 0, 0, 1058, 1059, 5, 95, 0, 0, 1059, 1060, 7, 7, 0, 0, 1060, 1061, 7, 2, 0, 0, 1061, 1062, 7, 5, 0, 0, 1062, 1063, 7, 3, 0, 0, 1063, 1064, 7, 23, 0, 0, 1064, 104, 1, 0, 0, 0, 1065, 1066, 7, 3, 0, 0, 1066, 1067, 7, 15, 0, 0, 1067, 1068, 7, 10, 0, 0, 1068, 1069, 7, 13, 0, 0, 1069, 1070, 7, 3, 0, 0, 1070, 1071, 7, 14, 0, 0, 1071, 1072, 7, 23, 0, 0, 1072, 1073, 5, 95, 0, 0, 1073, 1074, 7, 4, 0, 0, 1074, 1075, 7, 3, 0, 0, 1075, 1076, 7, 16, 0, 0, 1076, 1077, 7, 2, 0, 0, 1077, 106, 1, 0, 0, 0, 1078, 1079, 7, 5, 0, 0, 1079, 1080, 7, 3, 0, 0, 1080, 1081, 7, 16, 0, 0, 1081, 1082, 7, 2, 0, 0, 1082, 1083, 7, 20, 0, 0, 1083, 1084, 7, 10, 0, 0, 1084, 1085, 7, 4, 0, 0, 1085, 1086, 7, 23, 0, 0, 1086, 1087, 5, 95, 0, 0, 1087, 1088, 7, 12, 0, 0, 1088, 1089, 7, 8, 0, 0, 1089, 1090, 7, 2, 0, 0, 1090, 1091, 7, 14, 0, 0, 1091, 1092, 7, 7, 0, 0, 1092, 108, 1, 0, 0, 0, 1093, 1094, 7, 16, 0, 0, 1094, 1095, 7, 8, 0, 0, 1095, 1096, 7, 13, 0, 0, 1096, 1097, 7, 2, 0, 0, 1097, 1098, 5, 95, 0, 0, 1098, 1099, 7, 12, 0, 0, 1099, 1100, 7, 8, 0, 0, 1100, 1101, 7, 2, 0, 0, 1101, 1102, 7, 14, 0, 0, 1102, 1103, 7, 7, 0, 0, 1103, 110, 1, 0, 0, 0, 1104, 1105, 7, 16, 0, 0, 1105, 1106, 7, 8, 0, 0, 1106, 1107, 7, 13, 0, 0, 1107, 1108, 7, 2, 0, 0, 1108, 1109, 5, 95, 0, 0, 1109, 1110, 7, 24, 0, 0, 1110, 1111, 7, 10, 0, 0, 1111, 1112, 7, 15, 0, 0, 1112, 1113, 7, 2, 0, 0, 1113, 112, 1, 0, 0, 0, 1114, 1115, 7, 16, 0, 0, 1115, 1116, 7, 4, 0, 0, 1116, 1117, 7, 3, 0, 0, 1117, 1118, 7, 8, 0, 0, 1118, 1119, 7, 15, 0, 0, 1119, 1120, 7, 8, 0, 0, 1120, 1121, 7, 15, 0, 0, 1121, 1122, 7, 20, 0, 0, 1122, 1123, 5, 95, 0, 0, 1123, 1124, 7, 7, 0, 0, 1124, 1125, 7, 3, 0, 0, 1125, 1126, 7, 16, 0, 0, 1126, 1127, 7, 3, 0, 0, 1127, 1128, 5, 95, 0, 0, 1128, 1129, 7, 1, 0, 0, 1129, 1130, 7, 8, 0, 0, 1130, 1131, 7, 24, 0, 0, 1131, 1132, 7, 2, 0, 0, 1132, 114, 1, 0, 0, 0, 1133, 1134, 7, 3, 0, 0, 1134, 1135, 7, 15, 0, 0, 1135, 1136, 7, 10, 0, 0, 1136, 1137, 7, 13, 0, 0, 1137, 1138, 7, 3, 0, 0, 1138, 1139, 7, 14, 0, 0, 1139, 1140, 7, 23, 0, 0, 1140, 1141, 5, 95, 0, 0, 1141, 1142, 7, 1, 0, 0, 1142, 1143, 7, 5, 0, 0, 1143, 1144, 7, 10, 0, 0, 1144, 1145, 7, 4, 0, 0, 1145, 1146, 7, 2, 0, 0, 1146, 1147, 5, 95, 0, 0, 1147, 1148, 7, 16, 0, 0, 1148, 1149, 7, 6, 0, 0, 1149, 1150, 7, 4, 0, 0, 1150, 1151, 7, 2, 0, 0, 1151, 1152, 7, 1, 0, 0, 1152, 1153, 7, 6, 0, 0, 1153, 1154, 7, 10, 0, 0, 1154, 1155, 7, 14, 0, 0, 1155, 1156, 7, 7, 0, 0, 1156, 116, 1, 0, 0, 0, 1157, 1158, 7, 5, 0, 0, 1158, 1159, 7, 3, 0, 0, 1159, 1160, 7, 1, 0, 0, 1160, 1161, 7, 2, 0, 0, 1161, 118, 1, 0, 0, 0, 1162, 1163, 7, 8, 0, 0, 1163, 1164, 7, 15, 0, 0, 1164, 120, 1, 0, 0, 0, 1165, 1166, 7, 15, 0, 0, 1166, 1167, 7, 10, 0, 0, 1167, 1168, 7, 16, 0, 0, 1168, 122, 1, 0, 0, 0, 1169, 1170, 7, 10, 0, 0, 1170, 1171, 7, 4, 0, 0, 1171, 124, 1, 0, 0, 0, 1172, 1173, 7, 3, 0, 0, 1173, 1174, 7, 15, 0, 0, 1174, 1175, 7, 7, 0, 0, 1175, 126, 1, 0, 0, 0, 1176, 1177, 7, 21, 0, 0, 1177, 1178, 7, 10, 0, 0, 1178, 1179, 7, 4, 0, 0, 1179, 128, 1, 0, 0, 0, 1180, 1181, 7, 16, 0, 0, 1181, 1182, 7, 4, 0, 0, 1182, 1183, 7, 17, 0, 0, 1183, 1184, 7, 2, 0, 0, 1184, 130, 1, 0, 0, 0, 1185, 1186, 7, 12, 0, 0, 1186, 1187, 7, 3, 0, 0, 1187, 1188, 7, 14, 0, 0, 1188, 1189, 7, 1, 0, 0, 1189, 1190, 7, 2, 0, 0, 1190, 132, 1, 0, 0, 0, 1191, 1192, 7, 4, 0, 0, 1192, 1193, 7, 2, 0, 0, 1193, 1194, 7, 20, 0, 0, 1194, 1195, 7, 2, 0, 0, 1195, 1196, 7, 21, 0, 0, 1196, 1197, 7, 18, 0, 0, 1197, 134, 1, 0, 0, 0, 1198, 1199, 7, 5, 0, 0, 1199, 1200, 7, 10, 0, 0, 1200, 1201, 7, 15, 0, 0, 1201, 1202, 7, 19, 0, 0, 1202, 1203, 7, 2, 0, 0, 1203, 1204, 7, 4, 0, 0, 1204, 1205, 7, 16, 0, 0, 1205, 1206, 5, 95, 0, 0, 1206, 1207, 7, 16, 0, 0, 1207, 1208, 7, 24, 0, 0, 1208, 136, 1, 0, 0, 0, 1209, 1210, 7, 7, 0, 0, 1210, 1211, 7, 3, 0, 0, 1211, 1212, 7, 16, 0, 0, 1212, 1213, 7, 2, 0, 0, 1213, 1214, 7, 16, 0, 0, 1214, 1215, 7, 8, 0, 0, 1215, 1216, 7, 13, 0, 0, 1216, 1217, 7, 2, 0, 0, 1217, 138, 1, 0, 0, 0, 1218, 1219, 7, 7, 0, 0, 1219, 1220, 7, 3, 0, 0, 1220, 1221, 7, 23, 0, 0, 1221, 140, 1, 0, 0, 0, 1222, 1223, 7, 7, 0, 0, 1223, 1224, 7, 3, 0, 0, 1224, 1225, 7, 23, 0, 0, 1225, 1226, 5, 95, 0, 0, 1226, 1227, 7, 6, 0, 0, 1227, 1228, 7, 10, 0, 0, 1228, 1229, 7, 17, 0, 0, 1229, 1230, 7, 4, 0, 0, 1230, 142, 1, 0, 0, 0, 1231, 1232, 7, 7, 0, 0, 1232, 1233, 7, 3, 0, 0, 1233, 1234, 7, 23, 0, 0, 1234, 1235, 5, 95, 0, 0, 1235, 1236, 7, 13, 0, 0, 1236, 1237, 7, 8, 0, 0, 1237, 1238, 7, 5, 0, 0, 1238, 1239, 7, 4, 0, 0, 1239, 1240, 7, 10, 0, 0, 1240, 1241, 7, 1, 0, 0, 1241, 1242, 7, 2, 0, 0, 1242, 1243, 7, 5, 0, 0, 1243, 1244, 7, 10, 0, 0, 1244, 1245, 7, 15, 0, 0, 1245, 1246, 7, 7, 0, 0, 1246, 144, 1, 0, 0, 0, 1247, 1248, 7, 7, 0, 0, 1248, 1249, 7, 3, 0, 0, 1249, 1250, 7, 23, 0, 0, 1250, 1251, 5, 95, 0, 0, 1251, 1252, 7, 13, 0, 0, 1252, 1253, 7, 8, 0, 0, 1253, 1254, 7, 15, 0, 0, 1254, 1255, 7, 17, 0, 0, 1255, 1256, 7, 16, 0, 0, 1256, 1257, 7, 2, 0, 0, 1257, 146, 1, 0, 0, 0, 1258, 1259, 7, 7, 0, 0, 1259, 1260, 7, 3, 0, 0, 1260, 1261, 7, 23, 0, 0, 1261, 1262, 5, 95, 0, 0, 1262, 1263, 7, 10, 0, 0, 1263, 1264, 7, 12, 0, 0, 1264, 1265, 5, 95, 0, 0, 1265, 1266, 7, 23, 0, 0, 1266, 1267, 7, 2, 0, 0, 1267, 1268, 7, 3, 0, 0, 1268, 1269, 7, 4, 0, 0, 1269, 148, 1, 0, 0, 0, 1270, 1271, 7, 7, 0, 0, 1271, 1272, 7, 3, 0, 0, 1272, 1273, 7, 23, 0, 0, 1273, 1274, 5, 95, 0, 0, 1274, 1275, 7, 1, 0, 0, 1275, 1276, 7, 2, 0, 0, 1276, 1277, 7, 5, 0, 0, 1277, 1278, 7, 10, 0, 0, 1278, 1279, 7, 15, 0, 0, 1279, 1280, 7, 7, 0, 0, 1280, 150, 1, 0, 0, 0, 1281, 1282, 7, 6, 0, 0, 1282, 1283, 7, 10, 0, 0, 1283, 1284, 7, 17, 0, 0, 1284, 1285, 7, 4, 0, 0, 1285, 152, 1, 0, 0, 0, 1286, 1287, 7, 6, 0, 0, 1287, 1288, 7, 10, 0, 0, 1288, 1289, 7, 17, 0, 0, 1289, 1290, 7, 4, 0, 0, 1290, 1291, 5, 95, 0, 0, 1291, 1292, 7, 13, 0, 0, 1292, 1293, 7, 8, 0, 0, 1293, 1294, 7, 5, 0, 0, 1294, 1295, 7, 4, 0, 0, 1295, 1296, 7, 10, 0, 0, 1296, 1297, 7, 1, 0, 0, 1297, 1298, 7, 2, 0, 0, 1298, 1299, 7, 5, 0, 0, 1299, 1300, 7, 10, 0, 0, 1300, 1301, 7, 15, 0, 0, 1301, 1302, 7, 7, 0, 0, 1302, 154, 1, 0, 0, 0, 1303, 1304, 7, 6, 0, 0, 1304, 1305, 7, 10, 0, 0, 1305, 1306, 7, 17, 0, 0, 1306, 1307, 7, 4, 0, 0, 1307, 1308, 5, 95, 0, 0, 1308, 1309, 7, 13, 0, 0, 1309, 1310, 7, 8, 0, 0, 1310, 1311, 7, 15, 0, 0, 1311, 1312, 7, 17, 0, 0, 1312, 1313, 7, 16, 0, 0, 1313, 1314, 7, 2, 0, 0, 1314, 156, 1, 0, 0, 0, 1315, 1316, 7, 6, 0, 0, 1316, 1317, 7, 10, 0, 0, 1317, 1318, 7, 17, 0, 0, 1318, 1319, 7, 4, 0, 0, 1319, 1320, 5, 95, 0, 0, 1320, 1321, 7, 10, 0, 0, 1321, 1322, 7, 12, 0, 0, 1322, 1323, 5, 95, 0, 0, 1323, 1324, 7, 7, 0, 0, 1324, 1325, 7, 3, 0, 0, 1325, 1326, 7, 23, 0, 0, 1326, 158, 1, 0, 0, 0, 1327, 1328, 7, 6, 0, 0, 1328, 1329, 7, 10, 0, 0, 1329, 1330, 7, 17, 0, 0, 1330, 1331, 7, 4, 0, 0, 1331, 1332, 5, 95, 0, 0, 1332, 1333, 7, 1, 0, 0, 1333, 1334, 7, 2, 0, 0, 1334, 1335, 7, 5, 0, 0, 1335, 1336, 7, 10, 0, 0, 1336, 1337, 7, 15, 0, 0, 1337, 1338, 7, 7, 0, 0, 1338, 160, 1, 0, 0, 0, 1339, 1340, 7, 8, 0, 0, 1340, 1341, 7, 15, 0, 0, 1341, 1342, 7, 16, 0, 0, 1342, 1343, 7, 2, 0, 0, 1343, 1344, 7, 4, 0, 0, 1344, 1345, 7, 19, 0, 0, 1345, 1346, 7, 3, 0, 0, 1346, 1347, 7, 14, 0, 0, 1347, 162, 1, 0, 0, 0, 1348, 1349, 7, 13, 0, 0, 1349, 1350, 7, 8, 0, 0, 1350, 1351, 7, 5, 0, 0, 1351, 1352, 7, 4, 0, 0, 1352, 1353, 7, 10, 0, 0, 1353, 1354, 7, 1, 0, 0, 1354, 1355, 7, 2, 0, 0, 1355, 1356, 7, 5, 0, 0, 1356, 1357, 7, 10, 0, 0, 1357, 1358, 7, 15, 0, 0, 1358, 1359, 7, 7, 0, 0, 1359, 164, 1, 0, 0, 0, 1360, 1361, 7, 13, 0, 0, 1361, 1362, 7, 8, 0, 0, 1362, 1363, 7, 14, 0, 0, 1363, 1364, 7, 14, 0, 0, 1364, 1365, 7, 8, 0, 0, 1365, 1366, 7, 1, 0, 0, 1366, 1367, 7, 2, 0, 0, 1367, 1368, 7, 5, 0, 0, 1368, 1369, 7, 10, 0, 0, 1369, 1370, 7, 15, 0, 0, 1370, 1371, 7, 7, 0, 0, 1371, 166, 1, 0, 0, 0, 1372, 1373, 7, 13, 0, 0, 1373, 1374, 7, 8, 0, 0, 1374, 1375, 7, 15, 0, 0, 1375, 1376, 7, 17, 0, 0, 1376, 1377, 7, 16, 0, 0, 1377, 1378, 7, 2, 0, 0, 1378, 168, 1, 0, 0, 0, 1379, 1380, 7, 13, 0, 0, 1380, 1381, 7, 8, 0, 0, 1381, 1382, 7, 15, 0, 0, 1382, 1383, 7, 17, 0, 0, 1383, 1384, 7, 16, 0, 0, 1384, 1385, 7, 2, 0, 0, 1385, 1386, 5, 95, 0, 0, 1386, 1387, 7, 13, 0, 0, 1387, 1388, 7, 8, 0, 0, 1388, 1389, 7, 5, 0, 0, 1389, 1390, 7, 4, 0, 0, 1390, 1391, 7, 10, 0, 0, 1391, 1392, 7, 1, 0, 0, 1392, 1393, 7, 2, 0, 0, 1393, 1394, 7, 5, 0, 0, 1394, 1395, 7, 10, 0, 0, 1395, 1396, 7, 15, 0, 0, 1396, 1397, 7, 7, 0, 0, 1397, 170, 1, 0, 0, 0, 1398, 1399, 7, 13, 0, 0, 1399, 1400, 7, 8, 0, 0, 1400, 1401, 7, 15, 0, 0, 1401, 1402, 7, 17, 0, 0, 1402, 1403, 7, 16, 0, 0, 1403, 1404, 7, 2, 0, 0, 1404, 1405, 5, 95, 0, 0, 1405, 1406, 7, 10, 0, 0, 1406, 1407, 7, 12, 0, 0, 1407, 1408, 5, 95, 0, 0, 1408, 1409, 7, 7, 0, 0, 1409, 1410, 7, 3, 0, 0, 1410, 1411, 7, 23, 0, 0, 1411, 172, 1, 0, 0, 0, 1412, 1413, 7, 13, 0, 0, 1413, 1414, 7, 8, 0, 0, 1414, 1415, 7, 15, 0, 0, 1415, 1416, 7, 17, 0, 0, 1416, 1417, 7, 16, 0, 0, 1417, 1418, 7, 2, 0, 0, 1418, 1419, 5, 95, 0, 0, 1419, 1420, 7, 10, 0, 0, 1420, 1421, 7, 12, 0, 0, 1421, 1422, 5, 95, 0, 0, 1422, 1423, 7, 6, 0, 0, 1423, 1424, 7, 10, 0, 0, 1424, 1425, 7, 17, 0, 0, 1425, 1426, 7, 4, 0, 0, 1426, 174, 1, 0, 0, 0, 1427, 1428, 7, 13, 0, 0, 1428, 1429, 7, 8, 0, 0, 1429, 1430, 7, 15, 0, 0, 1430, 1431, 7, 17, 0, 0, 1431, 1432, 7, 16, 0, 0, 1432, 1433, 7, 2, 0, 0, 1433, 1434, 5, 95, 0, 0, 1434, 1435, 7, 1, 0, 0, 1435, 1436, 7, 2, 0, 0, 1436, 1437, 7, 5, 0, 0, 1437, 1438, 7, 10, 0, 0, 1438, 1439, 7, 15, 0, 0, 1439, 1440, 7, 7, 0, 0, 1440, 176, 1, 0, 0, 0, 1441, 1442, 7, 13, 0, 0, 1442, 1443, 7, 10, 0, 0, 1443, 1444, 7, 15, 0, 0, 1444, 1445, 7, 16, 0, 0, 1445, 1446, 7, 6, 0, 0, 1446, 178, 1, 0, 0, 0, 1447, 1448, 7, 13, 0, 0, 1448, 1449, 7, 10, 0, 0, 1449, 1450, 7, 15, 0, 0, 1450, 1451, 7, 16, 0, 0, 1451, 1452, 7, 6, 0, 0, 1452, 1453, 5, 95, 0, 0, 1453, 1454, 7, 10, 0, 0, 1454, 1455, 7, 12, 0, 0, 1455, 1456, 5, 95, 0, 0, 1456, 1457, 7, 23, 0, 0, 1457, 1458, 7, 2, 0, 0, 1458, 1459, 7, 3, 0, 0, 1459, 1460, 7, 4, 0, 0, 1460, 180, 1, 0, 0, 0, 1461, 1462, 7, 25, 0, 0, 1462, 1463, 7, 17, 0, 0, 1463, 1464, 7, 3, 0, 0, 1464, 1465, 7, 4, 0, 0, 1465, 1466, 7, 16, 0, 0, 1466, 1467, 7, 2, 0, 0, 1467, 1468, 7, 4, 0, 0, 1468, 182, 1, 0, 0, 0, 1469, 1470, 7, 1, 0, 0, 1470, 1471, 7, 2, 0, 0, 1471, 1472, 7, 5, 0, 0, 1472, 1473, 7, 10, 0, 0, 1473, 1474, 7, 15, 0, 0, 1474, 1475, 7, 7, 0, 0, 1475, 184, 1, 0, 0, 0, 1476, 1477, 7, 1, 0, 0, 1477, 1478, 7, 2, 0, 0, 1478, 1479, 7, 5, 0, 0, 1479, 1480, 7, 10, 0, 0, 1480, 1481, 7, 15, 0, 0, 1481, 1482, 7, 7, 0, 0, 1482, 1483, 5, 95, 0, 0, 1483, 1484, 7, 13, 0, 0, 1484, 1485, 7, 8, 0, 0, 1485, 1486, 7, 5, 0, 0, 1486, 1487, 7, 4, 0, 0, 1487, 1488, 7, 10, 0, 0, 1488, 1489, 7, 1, 0, 0, 1489, 1490, 7, 2, 0, 0, 1490, 1491, 7, 5, 0, 0, 1491, 1492, 7, 10, 0, 0, 1492, 1493, 7, 15, 0, 0, 1493, 1494, 7, 7, 0, 0, 1494, 186, 1, 0, 0, 0, 1495, 1496, 7, 1, 0, 0, 1496, 1497, 7, 2, 0, 0, 1497, 1498, 7, 5, 0, 0, 1498, 1499, 7, 10, 0, 0, 1499, 1500, 7, 15, 0, 0, 1500, 1501, 7, 7, 0, 0, 1501, 1502, 5, 95, 0, 0, 1502, 1503, 7, 10, 0, 0, 1503, 1504, 7, 12, 0, 0, 1504, 1505, 5, 95, 0, 0, 1505, 1506, 7, 13, 0, 0, 1506, 1507, 7, 8, 0, 0, 1507, 1508, 7, 15, 0, 0, 1508, 1509, 7, 17, 0, 0, 1509, 1510, 7, 16, 0, 0, 1510, 1511, 7, 2, 0, 0, 1511, 188, 1, 0, 0, 0, 1512, 1513, 7, 11, 0, 0, 1513, 1514, 7, 2, 0, 0, 1514, 1515, 7, 2, 0, 0, 1515, 1516, 7, 22, 0, 0, 1516, 190, 1, 0, 0, 0, 1517, 1518, 7, 11, 0, 0, 1518, 1519, 7, 2, 0, 0, 1519, 1520, 7, 2, 0, 0, 1520, 1521, 7, 22, 0, 0, 1521, 1522, 5, 95, 0, 0, 1522, 1523, 7, 10, 0, 0, 1523, 1524, 7, 12, 0, 0, 1524, 1525, 5, 95, 0, 0, 1525, 1526, 7, 23, 0, 0, 1526, 1527, 7, 2, 0, 0, 1527, 1528, 7, 3, 0, 0, 1528, 1529, 7, 4, 0, 0, 1529, 192, 1, 0, 0, 0, 1530, 1531, 7, 23, 0, 0, 1531, 1532, 7, 2, 0, 0, 1532, 1533, 7, 3, 0, 0, 1533, 1534, 7, 4, 0, 0, 1534, 194, 1, 0, 0, 0, 1535, 1536, 7, 23, 0, 0, 1536, 1537, 7, 2, 0, 0, 1537, 1538, 7, 3, 0, 0, 1538, 1539, 7, 4, 0, 0, 1539, 1540, 5, 95, 0, 0, 1540, 1541, 7, 13, 0, 0, 1541, 1542, 7, 10, 0, 0, 1542, 1543, 7, 15, 0, 0, 1543, 1544, 7, 16, 0, 0, 1544, 1545, 7, 6, 0, 0, 1545, 196, 1, 0, 0, 0, 1546, 1547, 7, 7, 0, 0, 1547, 1548, 7, 3, 0, 0, 1548, 1549, 7, 16, 0, 0, 1549, 1550, 7, 3, 0, 0, 1550, 1551, 7, 13, 0, 0, 1551, 1552, 7, 10, 0, 0, 1552, 1553, 7, 7, 0, 0, 1553, 1554, 7, 2, 0, 0, 1554, 1555, 7, 14, 0, 0, 1555, 198, 1, 0, 0, 0, 1556, 1557, 7, 14, 0, 0, 1557, 1558, 7, 10, 0, 0, 1558, 1559, 7, 10, 0, 0, 1559, 1560, 7, 22, 0, 0, 1560, 1561, 7, 17, 0, 0, 1561, 1562, 7, 18, 0, 0, 1562, 200, 1, 0, 0, 0, 1563, 1564, 7, 1, 0, 0, 1564, 1565, 7, 3, 0, 0, 1565, 1566, 7, 19, 0, 0, 1566, 1567, 7, 2, 0, 0, 1567, 1568, 7, 7, 0, 0, 1568, 1569, 7, 1, 0, 0, 1569, 1570, 7, 2, 0, 0, 1570, 1571, 7, 3, 0, 0, 1571, 1572, 7, 4, 0, 0, 1572, 1573, 7, 5, 0, 0, 1573, 1574, 7, 6, 0, 0, 1574, 202, 1, 0, 0, 0, 1575, 1576, 7, 8, 0, 0, 1576, 1577, 7, 15, 0, 0, 1577, 1578, 7, 16, 0, 0, 1578, 204, 1, 0, 0, 0, 1579, 1580, 7, 8, 0, 0, 1580, 1581, 7, 15, 0, 0, 1581, 1582, 7, 16, 0, 0, 1582, 1583, 7, 2, 0, 0, 1583, 1584, 7, 20, 0, 0, 1584, 1585, 7, 2, 0, 0, 1585, 1586, 7, 4, 0, 0, 1586, 206, 1, 0, 0, 0, 1587, 1588, 7, 7, 0, 0, 1588, 1589, 7, 10, 0, 0, 1589, 1590, 7, 17, 0, 0, 1590, 1591, 7, 9, 0, 0, 1591, 1592, 7, 14, 0, 0, 1592, 1593, 7, 2, 0, 0, 1593, 208, 1, 0, 0, 0, 1594, 1595, 7, 14, 0, 0, 1595, 1596, 7, 10, 0, 0, 1596, 1597, 7, 15, 0, 0, 1597, 1598, 7, 20, 0, 0, 1598, 210, 1, 0, 0, 0, 1599, 1600, 7, 12, 0, 0, 1600, 1601, 7, 14, 0, 0, 1601, 1602, 7, 10, 0, 0, 1602, 1603, 7, 3, 0, 0, 1603, 1604, 7, 16, 0, 0, 1604, 212, 1, 0, 0, 0, 1605, 1606, 7, 1, 0, 0, 1606, 1607, 7, 16, 0, 0, 1607, 1608, 7, 4, 0, 0, 1608, 1609, 7, 8, 0, 0, 1609, 1610, 7, 15, 0, 0, 1610, 1611, 7, 20, 0, 0, 1611, 214, 1, 0, 0, 0, 1612, 1613, 7, 9, 0, 0, 1613, 1614, 7, 10, 0, 0, 1614, 1615, 7, 10, 0, 0, 1615, 1616, 7, 14, 0, 0, 1616, 1617, 7, 2, 0, 0, 1617, 1618, 7, 3, 0, 0, 1618, 1619, 7, 15, 0, 0, 1619, 216, 1, 0, 0, 0, 1620, 1621, 5, 124, 0, 0, 1621, 218, 1, 0, 0, 0, 1622, 1623, 5, 44, 0, 0, 1623, 220, 1, 0, 0, 0, 1624, 1625, 5, 46, 0, 0, 1625, 222, 1, 0, 0, 0, 1626, 1627, 5, 61, 0, 0, 1627, 224, 1, 0, 0, 0, 1628, 1629, 5, 62, 0, 0, 1629, 226, 1, 0, 0, 0, 1630, 1631, 5, 60, 0, 0, 1631, 228, 1, 0, 0, 0, 1632, 1633, 5, 60, 0, 0, 1633, 1634, 5, 61, 0, 0, 1634, 230, 1, 0, 0, 0, 1635, 1636, 5, 62, 0, 0, 1636, 1637, 5, 61, 0, 0, 1637, 232, 1, 0, 0, 0, 1638, 1639, 5, 33, 0, 0, 1639, 1640, 5, 61, 0, 0, 1640, 234, 1, 0, 0, 0, 1641, 1642, 5, 43, 0, 0, 1642, 236, 1, 0, 0, 0, 1643, 1644, 5, 45, 0, 0, 1644, 238, 1, 0, 0, 0, 1645, 1646, 5, 42, 0, 0, 1646, 240, 1, 0, 0, 0, 1647, 1648, 5, 47, 0, 0, 1648, 242, 1, 0, 0, 0, 1649, 1650, 5, 37, 0, 0, 1650, 244, 1, 0, 0, 0, 1651, 1652, 5, 33, 0, 0, 1652, 246, 1, 0, 0, 0, 1653, 1654, 5, 58, 0, 0, 1654, 248, 1, 0, 0, 0, 1655, 1656, 5, 40, 0, 0, 1656, 250, 1, 0, 0, 0, 1657, 1658, 5, 41, 0, 0, 1658, 252, 1, 0, 0, 0, 1659, 1660, 5, 91, 0, 0, 1660, 254, 1, 0, 0, 0, 1661, 1662, 5, 93, 0, 0, 1662, 256, 1, 0, 0, 0, 1663, 1664, 5, 39, 0, 0, 1664, 258, 1, 0, 0, 0, 1665, 1666, 5, 34, 0, 0, 1666, 260, 1, 0, 0, 0, 1667, 1668, 5, 96, 0, 0, 1668, 262, 1, 0, 0, 0, 1669, 1670, 5, 126, 0, 0, 1670, 264, 1, 0, 0, 0, 1671, 1672, 5, 38, 0, 0, 1672, 266, 1, 0, 0, 0, 1673, 1674, 5, 94, 0, 0, 1674, 268, 1, 0, 0, 0, 1675, 1676, 7, 3, 0, 0, 1676, 1677, 7, 19, 0, 0, 1677, 1678, 7, 20, 0, 0, 1678, 270, 1, 0, 0, 0, 1679, 1680, 7, 5, 0, 0, 1680, 1681, 7, 10, 0, 0, 1681, 1682, 7, 17, 0, 0, 1682, 1683, 7, 15, 0, 0, 1683, 1684, 7, 16, 0, 0, 1684, 272, 1, 0, 0, 0, 1685, 1686, 7, 7, 0, 0, 1686, 1687, 7, 8, 0, 0, 1687, 1688, 7, 1, 0, 0, 1688, 1689, 7, 16, 0, 0, 1689, 1690, 7, 8, 0, 0, 1690, 1691, 7, 15, 0, 0, 1691, 1692, 7, 5, 0, 0, 1692, 1693, 7, 16, 0, 0, 1693, 1694, 5, 95, 0, 0, 1694, 1695, 7, 5, 0, 0, 1695, 1696, 7, 10, 0, 0, 1696, 1697, 7, 17, 0, 0, 1697, 1698, 7, 15, 0, 0, 1698, 1699, 7, 16, 0, 0, 1699, 274, 1, 0, 0, 0, 1700, 1701, 7, 2, 0, 0, 1701, 1702, 7, 1, 0, 0, 1702, 1703, 7, 16, 0, 0, 1703, 1704, 7, 7, 0, 0, 1704, 1705, 7, 5, 0, 0, 1705, 276, 1, 0, 0, 0, 1706, 1707, 7, 2, 0, 0, 1707, 1708, 7, 1, 0, 0, 1708, 1709, 7, 16, 0, 0, 1709, 1710, 7, 7, 0, 0, 1710, 1711, 7, 5, 0, 0, 1711, 1712, 5, 95, 0, 0, 1712, 1713, 7, 2, 0, 0, 1713, 1714, 7, 4, 0, 0, 1714, 1715, 7, 4, 0, 0, 1715, 1716, 7, 10, 0, 0, 1716, 1717, 7, 4, 0, 0, 1717, 278, 1, 0, 0, 0, 1718, 1719, 7, 13, 0, 0, 1719, 1720, 7, 3, 0, 0, 1720, 1721, 7, 21, 0, 0, 1721, 280, 1, 0, 0, 0, 1722, 1723, 7, 13, 0, 0, 1723, 1724, 7, 2, 0, 0, 1724, 1725, 7, 3, 0, 0, 1725, 1726, 7, 15, 0, 0, 1726, 282, 1, 0, 0, 0, 1727, 1728, 7, 13, 0, 0, 1728, 1729, 7, 2, 0, 0, 1729, 1730, 7, 7, 0, 0, 1730, 1731, 7, 8, 0, 0, 1731, 1732, 7, 3, 0, 0, 1732, 1733, 7, 15, 0, 0, 1733, 284, 1, 0, 0, 0, 1734, 1735, 7, 13, 0, 0, 1735, 1736, 7, 8, 0, 0, 1736, 1737, 7, 15, 0, 0, 1737, 286, 1, 0, 0, 0, 1738, 1739, 7, 13, 0, 0, 1739, 1740, 7, 10, 0, 0, 1740, 1741, 7, 7, 0, 0, 1741, 1742, 7, 2, 0, 0, 1742, 288, 1, 0, 0, 0, 1743, 1744, 7, 4, 0, 0, 1744, 1745, 7, 3, 0, 0, 1745, 1746, 7, 15, 0, 0, 1746, 1747, 7, 20, 0, 0, 1747, 1748, 7, 2, 0, 0, 1748, 290, 1, 0, 0, 0, 1749, 1750, 7, 1, 0, 0, 1750, 1751, 7, 16, 0, 0, 1751, 1752, 7, 7, 0, 0, 1752, 1753, 7, 2, 0, 0, 1753, 1754, 7, 19, 0, 0, 1754, 292, 1, 0, 0, 0, 1755, 1756, 7, 1, 0, 0, 1756, 1757, 7, 16, 0, 0, 1757, 1758, 7, 7, 0, 0, 1758, 1759, 7, 2, 0, 0, 1759, 1760, 7, 19, 0, 0, 1760, 1761, 7, 18, 0, 0, 1761, 294, 1, 0, 0, 0, 1762, 1763, 7, 1, 0, 0, 1763, 1764, 7, 17, 0, 0, 1764, 1765, 7, 13, 0, 0, 1765, 296, 1, 0, 0, 0, 1766, 1767, 7, 1, 0, 0, 1767, 1768, 7, 17, 0, 0, 1768, 1769, 7, 13, 0, 0, 1769, 1770, 7, 1, 0, 0, 1770, 1771, 7, 25, 0, 0, 1771, 298, 1, 0, 0, 0, 1772, 1773, 7, 19, 0, 0, 1773, 1774, 7, 3, 0, 0, 1774, 1775, 7, 4, 0, 0, 1775, 1776, 5, 95, 0, 0, 1776, 1777, 7, 1, 0, 0, 1777, 1778, 7, 3, 0, 0, 1778, 1779, 7, 13, 0, 0, 1779, 1780, 7, 18, 0, 0, 1780, 300, 1, 0, 0, 0, 1781, 1782, 7, 19, 0, 0, 1782, 1783, 7, 3, 0, 0, 1783, 1784, 7, 4, 0, 0, 1784, 1785, 5, 95, 0, 0, 1785, 1786, 7, 18, 0, 0, 1786, 1787, 7, 10, 0, 0, 1787, 1788, 7, 18, 0, 0, 1788, 302, 1, 0, 0, 0, 1789, 1790, 7, 1, 0, 0, 1790, 1791, 7, 16, 0, 0, 1791, 1792, 7, 7, 0, 0, 1792, 1793, 7, 7, 0, 0, 1793, 1794, 7, 2, 0, 0, 1794, 1795, 7, 19, 0, 0, 1795, 1796, 5, 95, 0, 0, 1796, 1797, 7, 1, 0, 0, 1797, 1798, 7, 3, 0, 0, 1798, 1799, 7, 13, 0, 0, 1799, 1800, 7, 18, 0, 0, 1800, 304, 1, 0, 0, 0, 1801, 1802, 7, 1, 0, 0, 1802, 1803, 7, 16, 0, 0, 1803, 1804, 7, 7, 0, 0, 1804, 1805, 7, 7, 0, 0, 1805, 1806, 7, 2, 0, 0, 1806, 1807, 7, 19, 0, 0, 1807, 1808, 5, 95, 0, 0, 1808, 1809, 7, 18, 0, 0, 1809, 1810, 7, 10, 0, 0, 1810, 1811, 7, 18, 0, 0, 1811, 306, 1, 0, 0, 0, 1812, 1813, 7, 18, 0, 0, 1813, 1814, 7, 2, 0, 0, 1814, 1815, 7, 4, 0, 0, 1815, 1816, 7, 5, 0, 0, 1816, 1817, 7, 2, 0, 0, 1817, 1818, 7, 15, 0, 0, 1818, 1819, 7, 16, 0, 0, 1819, 1820, 7, 8, 0, 0, 1820, 1821, 7, 14, 0, 0, 1821, 1822, 7, 2, 0, 0, 1822, 308, 1, 0, 0, 0, 1823, 1824, 7, 16, 0, 0, 1824, 1825, 7, 3, 0, 0, 1825, 1826, 7, 22, 0, 0, 1826, 1827, 7, 2, 0, 0, 1827, 310, 1, 0, 0, 0, 1828, 1829, 7, 12, 0, 0, 1829, 1830, 7, 8, 0, 0, 1830, 1831, 7, 4, 0, 0, 1831, 1832, 7, 1, 0, 0, 1832, 1833, 7, 16, 0, 0, 1833, 312, 1, 0, 0, 0, 1834, 1835, 7, 14, 0, 0, 1835, 1836, 7, 3, 0, 0, 1836, 1837, 7, 1, 0, 0, 1837, 1838, 7, 16, 0, 0, 1838, 314, 1, 0, 0, 0, 1839, 1840, 7, 14, 0, 0, 1840, 1841, 7, 8, 0, 0, 1841, 1842, 7, 1, 0, 0, 1842, 1843, 7, 16, 0, 0, 1843, 316, 1, 0, 0, 0, 1844, 1845, 7, 19, 0, 0, 1845, 1846, 7, 3, 0, 0, 1846, 1847, 7, 14, 0, 0, 1847, 1848, 7, 17, 0, 0, 1848, 1849, 7, 2, 0, 0, 1849, 1850, 7, 1, 0, 0, 1850, 318, 1, 0, 0, 0, 1851, 1852, 7, 2, 0, 0, 1852, 1853, 7, 3, 0, 0, 1853, 1854, 7, 4, 0, 0, 1854, 1855, 7, 14, 0, 0, 1855, 1856, 7, 8, 0, 0, 1856, 1857, 7, 2, 0, 0, 1857, 1858, 7, 1, 0, 0, 1858, 1859, 7, 16, 0, 0, 1859, 320, 1, 0, 0, 0, 1860, 1861, 7, 2, 0, 0, 1861, 1862, 7, 3, 0, 0, 1862, 1863, 7, 4, 0, 0, 1863, 1864, 7, 14, 0, 0, 1864, 1865, 7, 8, 0, 0, 1865, 1866, 7, 2, 0, 0, 1866, 1867, 7, 1, 0, 0, 1867, 1868, 7, 16, 0, 0, 1868, 1869, 5, 95, 0, 0, 1869, 1870, 7, 16, 0, 0, 1870, 1871, 7, 8, 0, 0, 1871, 1872, 7, 13, 0, 0, 1872, 1873, 7, 2, 0, 0, 1873, 322, 1, 0, 0, 0, 1874, 1875, 7, 14, 0, 0, 1875, 1876, 7, 3, 0, 0, 1876, 1877, 7, 16, 0, 0, 1877, 1878, 7, 2, 0, 0, 1878, 1879, 7, 1, 0, 0, 1879, 1880, 7, 16, 0, 0, 1880, 324, 1, 0, 0, 0, 1881, 1882, 7, 14, 0, 0, 1882, 1883, 7, 3, 0, 0, 1883, 1884, 7, 16, 0, 0, 1884, 1885, 7, 2, 0, 0, 1885, 1886, 7, 1, 0, 0, 1886, 1887, 7, 16, 0, 0, 1887, 1888, 5, 95, 0, 0, 1888, 1889, 7, 16, 0, 0, 1889, 1890, 7, 8, 0, 0, 1890, 1891, 7, 13, 0, 0, 1891, 1892, 7, 2, 0, 0, 1892, 326, 1, 0, 0, 0, 1893, 1894, 7, 18, 0, 0, 1894, 1895, 7, 2, 0, 0, 1895, 1896, 7, 4, 0, 0, 1896, 1897, 5, 95, 0, 0, 1897, 1898, 7, 7, 0, 0, 1898, 1899, 7, 3, 0, 0, 1899, 1900, 7, 23, 0, 0, 1900, 328, 1, 0, 0, 0, 1901, 1902, 7, 18, 0, 0, 1902, 1903, 7, 2, 0, 0, 1903, 1904, 7, 4, 0, 0, 1904, 1905, 5, 95, 0, 0, 1905, 1906, 7, 6, 0, 0, 1906, 1907, 7, 10, 0, 0, 1907, 1908, 7, 17, 0, 0, 1908, 1909, 7, 4, 0, 0, 1909, 330, 1, 0, 0, 0, 1910, 1911, 7, 18, 0, 0, 1911, 1912, 7, 2, 0, 0, 1912, 1913, 7, 4, 0, 0, 1913, 1914, 5, 95, 0, 0, 1914, 1915, 7, 13, 0, 0, 1915, 1916, 7, 8, 0, 0, 1916, 1917, 7, 15, 0, 0, 1917, 1918, 7, 17, 0, 0, 1918, 1919, 7, 16, 0, 0, 1919, 1920, 7, 2, 0, 0, 1920, 332, 1, 0, 0, 0, 1921, 1922, 7, 18, 0, 0, 1922, 1923, 7, 2, 0, 0, 1923, 1924, 7, 4, 0, 0, 1924, 1925, 5, 95, 0, 0, 1925, 1926, 7, 1, 0, 0, 1926, 1927, 7, 2, 0, 0, 1927, 1928, 7, 5, 0, 0, 1928, 1929, 7, 10, 0, 0, 1929, 1930, 7, 15, 0, 0, 1930, 1931, 7, 7, 0, 0, 1931, 334, 1, 0, 0, 0, 1932, 1933, 7, 4, 0, 0, 1933, 1934, 7, 3, 0, 0, 1934, 1935, 7, 16, 0, 0, 1935, 1936, 7, 2, 0, 0, 1936, 336, 1, 0, 0, 0, 1937, 1938, 7, 1, 0, 0, 1938, 1939, 7, 18, 0, 0, 1939, 1940, 7, 3, 0, 0, 1940, 1941, 7, 4, 0, 0, 1941, 1942, 7, 22, 0, 0, 1942, 1943, 7, 14, 0, 0, 1943, 1944, 7, 8, 0, 0, 1944, 1945, 7, 15, 0, 0, 1945, 1946, 7, 2, 0, 0, 1946, 338, 1, 0, 0, 0, 1947, 1948, 7, 5, 0, 0, 1948, 340, 1, 0, 0, 0, 1949, 1950, 7, 7, 0, 0, 1950, 1951, 7, 5, 0, 0, 1951, 342, 1, 0, 0, 0, 1952, 1953, 7, 3, 0, 0, 1953, 1954, 7, 9, 0, 0, 1954, 1955, 7, 1, 0, 0, 1955, 344, 1, 0, 0, 0, 1956, 1957, 7, 5, 0, 0, 1957, 1958, 7, 9, 0, 0, 1958, 1959, 7, 4, 0, 0, 1959, 1960, 7, 16, 0, 0, 1960, 346, 1, 0, 0, 0, 1961, 1962, 7, 5, 0, 0, 1962, 1963, 7, 2, 0, 0, 1963, 1964, 7, 8, 0, 0, 1964, 1965, 7, 14, 0, 0, 1965, 348, 1, 0, 0, 0, 1966, 1967, 7, 5, 0, 0, 1967, 1968, 7, 2, 0, 0, 1968, 1969, 7, 8, 0, 0, 1969, 1970, 7, 14, 0, 0, 1970, 1971, 7, 8, 0, 0, 1971, 1972, 7, 15, 0, 0, 1972, 1973, 7, 20, 0, 0, 1973, 350, 1, 0, 0, 0, 1974, 1975, 7, 5, 0, 0, 1975, 1976, 7, 10, 0, 0, 1976, 1977, 7, 15, 0, 0, 1977, 1978, 7, 19, 0, 0, 1978, 352, 1, 0, 0, 0, 1979, 1980, 7, 5, 0, 0, 1980, 1981, 7, 4, 0, 0, 1981, 1982, 7, 5, 0, 0, 1982, 1983, 5, 51, 0, 0, 1983, 1984, 5, 50, 0, 0, 1984, 354, 1, 0, 0, 0, 1985, 1986, 7, 2, 0, 0, 1986, 356, 1, 0, 0, 0, 1987, 1988, 7, 2, 0, 0, 1988, 1989, 7, 21, 0, 0, 1989, 1990, 7, 18, 0, 0, 1990, 358, 1, 0, 0, 0, 1991, 1992, 7, 12, 0, 0, 1992, 1993, 7, 14, 0, 0, 1993, 1994, 7, 10, 0, 0, 1994, 1995, 7, 10, 0, 0, 1995, 1996, 7, 4, 0, 0, 1996, 360, 1, 0, 0, 0, 1997, 1998, 7, 14, 0, 0, 1998, 1999, 7, 15, 0, 0, 1999, 362, 1, 0, 0, 0, 2000, 2001, 7, 14, 0, 0, 2001, 2002, 7, 10, 0, 0, 2002, 2003, 7, 20, 0, 0, 2003, 364, 1, 0, 0, 0, 2004, 2005, 7, 14, 0, 0, 2005, 2006, 7, 10, 0, 0, 2006, 2007, 7, 20, 0, 0, 2007, 2008, 5, 49, 0, 0, 2008, 2009, 5, 48, 0, 0, 2009, 366, 1, 0, 0, 0, 2010, 2011, 7, 14, 0, 0, 2011, 2012, 7, 10, 0, 0, 2012, 2013, 7, 20, 0, 0, 2013, 2014, 5, 50, 0, 0, 2014, 368, 1, 0, 0, 0, 2015, 2016, 7, 13, 0, 0, 2016, 2017, 7, 10, 0, 0, 2017, 2018, 7, 7, 0, 0, 2018, 370, 1, 0, 0, 0, 2019, 2020, 7, 18, 0, 0, 2020, 2021, 7, 8, 0, 0, 2021, 372, 1, 0, 0, 0, 2022, 2023, 7, 18, 0, 0, 2023, 2024, 7, 10, 0, 0, 2024, 2025, 7, 1, 0, 0, 2025, 2026, 7, 8, 0, 0, 2026, 2027, 7, 16, 0, 0, 2027, 2028, 7, 8, 0, 0, 2028, 2029, 7, 10, 0, 0, 2029, 2030, 7, 15, 0, 0, 2030, 374, 1, 0, 0, 0, 2031, 2032, 7, 18, 0, 0, 2032, 2033, 7, 10, 0, 0, 2033, 2034, 7, 11, 0, 0, 2034, 376, 1, 0, 0, 0, 2035, 2036, 7, 18, 0, 0, 2036, 2037, 7, 10, 0, 0, 2037, 2038, 7, 11, 0, 0, 2038, 2039, 7, 2, 0, 0, 2039, 2040, 7, 4, 0, 0, 2040, 378, 1, 0, 0, 0, 2041, 2042, 7, 4, 0, 0, 2042, 2043, 7, 3, 0, 0, 2043, 2044, 7, 15, 0, 0, 2044, 2045, 7, 7, 0, 0, 2045, 380, 1, 0, 0, 0, 2046, 2047, 7, 4, 0, 0, 2047, 2048, 7, 10, 0, 0, 2048, 2049, 7, 17, 0, 0, 2049, 2050, 7, 15, 0, 0, 2050, 2051, 7, 7, 0, 0, 2051, 382, 1, 0, 0, 0, 2052, 2053, 7, 1, 0, 0, 2053, 2054, 7, 8, 0, 0, 2054, 2055, 7, 20, 0, 0, 2055, 2056, 7, 15, 0, 0, 2056, 384, 1, 0, 0, 0, 2057, 2058, 7, 1, 0, 0, 2058, 2059, 7, 25, 0, 0, 2059, 2060, 7, 4, 0, 0, 2060, 2061, 7, 16, 0, 0, 2061, 386, 1, 0, 0, 0, 2062, 2063, 7, 16, 0, 0, 2063, 2064, 7, 4, 0, 0, 2064, 2065, 7, 17, 0, 0, 2065, 2066, 7, 15, 0, 0, 2066, 2067, 7, 5, 0, 0, 2067, 2068, 7, 3, 0, 0, 2068, 2069, 7, 16, 0, 0, 2069, 2070, 7, 2, 0, 0, 2070, 388, 1, 0, 0, 0, 2071, 2072, 7, 3, 0, 0, 2072, 2073, 7, 5, 0, 0, 2073, 2074, 7, 10, 0, 0, 2074, 2075, 7, 1, 0, 0, 2075, 390, 1, 0, 0, 0, 2076, 2077, 7, 3, 0, 0, 2077, 2078, 7, 1, 0, 0, 2078, 2079, 7, 8, 0, 0, 2079, 2080, 7, 15, 0, 0, 2080, 392, 1, 0, 0, 0, 2081, 2082, 7, 3, 0, 0, 2082, 2083, 7, 16, 0, 0, 2083, 2084, 7, 3, 0, 0, 2084, 2085, 7, 15, 0, 0, 2085, 394, 1, 0, 0, 0, 2086, 2087, 7, 3, 0, 0, 2087, 2088, 7, 16, 0, 0, 2088, 2089, 7, 3, 0, 0, 2089, 2090, 7, 15, 0, 0, 2090, 2091, 5, 50, 0, 0, 2091, 396, 1, 0, 0, 0, 2092, 2093, 7, 5, 0, 0, 2093, 2094, 7, 10, 0, 0, 2094, 2095, 7, 1, 0, 0, 2095, 398, 1, 0, 0, 0, 2096, 2097, 7, 5, 0, 0, 2097, 2098, 7, 10, 0, 0, 2098, 2099, 7, 16, 0, 0, 2099, 400, 1, 0, 0, 0, 2100, 2101, 7, 7, 0, 0, 2101, 2102, 7, 2, 0, 0, 2102, 2103, 7, 20, 0, 0, 2103, 2104, 7, 4, 0, 0, 2104, 2105, 7, 2, 0, 0, 2105, 2106, 7, 2, 0, 0, 2106, 2107, 7, 1, 0, 0, 2107, 402, 1, 0, 0, 0, 2108, 2109, 7, 4, 0, 0, 2109, 2110, 7, 3, 0, 0, 2110, 2111, 7, 7, 0, 0, 2111, 2112, 7, 8, 0, 0, 2112, 2113, 7, 3, 0, 0, 2113, 2114, 7, 15, 0, 0, 2114, 2115, 7, 1, 0, 0, 2115, 404, 1, 0, 0, 0, 2116, 2117, 7, 1, 0, 0, 2117, 2118, 7, 8, 0, 0, 2118, 2119, 7, 15, 0, 0, 2119, 406, 1, 0, 0, 0, 2120, 2121, 7, 16, 0, 0, 2121, 2122, 7, 3, 0, 0, 2122, 2123, 7, 15, 0, 0, 2123, 408, 1, 0, 0, 0, 2124, 2125, 7, 3, 0, 0, 2125, 2126, 7, 7, 0, 0, 2126, 2127, 7, 7, 0, 0, 2127, 2128, 7, 7, 0, 0, 2128, 2129, 7, 3, 0, 0, 2129, 2130, 7, 16, 0, 0, 2130, 2131, 7, 2, 0, 0, 2131, 410, 1, 0, 0, 0, 2132, 2133, 7, 3, 0, 0, 2133, 2134, 7, 7, 0, 0, 2134, 2135, 7, 7, 0, 0, 2135, 2136, 7, 16, 0, 0, 2136, 2137, 7, 8, 0, 0, 2137, 2138, 7, 13, 0, 0, 2138, 2139, 7, 2, 0, 0, 2139, 412, 1, 0, 0, 0, 2140, 2141, 7, 5, 0, 0, 2141, 2142, 7, 17, 0, 0, 2142, 2143, 7, 4, 0, 0, 2143, 2144, 7, 7, 0, 0, 2144, 2145, 7, 3, 0, 0, 2145, 2146, 7, 16, 0, 0, 2146, 2147, 7, 2, 0, 0, 2147, 414, 1, 0, 0, 0, 2148, 2149, 7, 5, 0, 0, 2149, 2150, 7, 17, 0, 0, 2150, 2151, 7, 4, 0, 0, 2151, 2152, 7, 4, 0, 0, 2152, 2153, 7, 2, 0, 0, 2153, 2154, 7, 15, 0, 0, 2154, 2155, 7, 16, 0, 0, 2155, 2156, 5, 95, 0, 0, 2156, 2157, 7, 7, 0, 0, 2157, 2158, 7, 3, 0, 0, 2158, 2159, 7, 16, 0, 0, 2159, 2160, 7, 2, 0, 0, 2160, 416, 1, 0, 0, 0, 2161, 2162, 7, 5, 0, 0, 2162, 2163, 7, 17, 0, 0, 2163, 2164, 7, 4, 0, 0, 2164, 2165, 7, 4, 0, 0, 2165, 2166, 7, 2, 0, 0, 2166, 2167, 7, 15, 0, 0, 2167, 2168, 7, 16, 0, 0, 2168, 2169, 5, 95, 0, 0, 2169, 2170, 7, 16, 0, 0, 2170, 2171, 7, 8, 0, 0, 2171, 2172, 7, 13, 0, 0, 2172, 2173, 7, 2, 0, 0, 2173, 418, 1, 0, 0, 0, 2174, 2175, 7, 5, 0, 0, 2175, 2176, 7, 17, 0, 0, 2176, 2177, 7, 4, 0, 0, 2177, 2178, 7, 4, 0, 0, 2178, 2179, 7, 2, 0, 0, 2179, 2180, 7, 15, 0, 0, 2180, 2181, 7, 16, 0, 0, 2181, 2182, 5, 95, 0, 0, 2182, 2183, 7, 16, 0, 0, 2183, 2184, 7, 8, 0, 0, 2184, 2185, 7, 13, 0, 0, 2185, 2186, 7, 2, 0, 0, 2186, 2187, 7, 1, 0, 0, 2187, 2188, 7, 16, 0, 0, 2188, 2189, 7, 3, 0, 0, 2189, 2190, 7, 13, 0, 0, 2190, 2191, 7, 18, 0, 0, 2191, 420, 1, 0, 0, 0, 2192, 2193, 7, 5, 0, 0, 2193, 2194, 7, 17, 0, 0, 2194, 2195, 7, 4, 0, 0, 2195, 2196, 7, 16, 0, 0, 2196, 2197, 7, 8, 0, 0, 2197, 2198, 7, 13, 0, 0, 2198, 2199, 7, 2, 0, 0, 2199, 422, 1, 0, 0, 0, 2200, 2201, 7, 7, 0, 0, 2201, 2202, 7, 3, 0, 0, 2202, 2203, 7, 16, 0, 0, 2203, 2204, 7, 2, 0, 0, 2204, 424, 1, 0, 0, 0, 2205, 2206, 7, 7, 0, 0, 2206, 2207, 7, 3, 0, 0, 2207, 2208, 7, 16, 0, 0, 2208, 2209, 7, 2, 0, 0, 2209, 2210, 7, 7, 0, 0, 2210, 2211, 7, 8, 0, 0, 2211, 2212, 7, 12, 0, 0, 2212, 2213, 7, 12, 0, 0, 2213, 426, 1, 0, 0, 0, 2214, 2215, 7, 7, 0, 0, 2215, 2216, 7, 3, 0, 0, 2216, 2217, 7, 16, 0, 0, 2217, 2218, 7, 2, 0, 0, 2218, 2219, 5, 95, 0, 0, 2219, 2220, 7, 3, 0, 0, 2220, 2221, 7, 7, 0, 0, 2221, 2222, 7, 7, 0, 0, 2222, 428, 1, 0, 0, 0, 2223, 2224, 7, 7, 0, 0, 2224, 2225, 7, 3, 0, 0, 2225, 2226, 7, 16, 0, 0, 2226, 2227, 7, 2, 0, 0, 2227, 2228, 5, 95, 0, 0, 2228, 2229, 7, 12, 0, 0, 2229, 2230, 7, 10, 0, 0, 2230, 2231, 7, 4, 0, 0, 2231, 2232, 7, 13, 0, 0, 2232, 2233, 7, 3, 0, 0, 2233, 2234, 7, 16, 0, 0, 2234, 430, 1, 0, 0, 0, 2235, 2236, 7, 7, 0, 0, 2236, 2237, 7, 3, 0, 0, 2237, 2238, 7, 16, 0, 0, 2238, 2239, 7, 2, 0, 0, 2239, 2240, 5, 95, 0, 0, 2240, 2241, 7, 1, 0, 0, 2241, 2242, 7, 17, 0, 0, 2242, 2243, 7, 9, 0, 0, 2243, 432, 1, 0, 0, 0, 2244, 2245, 7, 7, 0, 0, 2245, 2246, 7, 3, 0, 0, 2246, 2247, 7, 23, 0, 0, 2247, 2248, 7, 15, 0, 0, 2248, 2249, 7, 3, 0, 0, 2249, 2250, 7, 13, 0, 0, 2250, 2251, 7, 2, 0, 0, 2251, 434, 1, 0, 0, 0, 2252, 2253, 7, 7, 0, 0, 2253, 2254, 7, 3, 0, 0, 2254, 2255, 7, 23, 0, 0, 2255, 2256, 7, 10, 0, 0, 2256, 2257, 7, 12, 0, 0, 2257, 2258, 7, 13, 0, 0, 2258, 2259, 7, 10, 0, 0, 2259, 2260, 7, 15, 0, 0, 2260, 2261, 7, 16, 0, 0, 2261, 2262, 7, 6, 0, 0, 2262, 436, 1, 0, 0, 0, 2263, 2264, 7, 7, 0, 0, 2264, 2265, 7, 3, 0, 0, 2265, 2266, 7, 23, 0, 0, 2266, 2267, 7, 10, 0, 0, 2267, 2268, 7, 12, 0, 0, 2268, 2269, 7, 11, 0, 0, 2269, 2270, 7, 2, 0, 0, 2270, 2271, 7, 2, 0, 0, 2271, 2272, 7, 22, 0, 0, 2272, 438, 1, 0, 0, 0, 2273, 2274, 7, 7, 0, 0, 2274, 2275, 7, 3, 0, 0, 2275, 2276, 7, 23, 0, 0, 2276, 2277, 7, 10, 0, 0, 2277, 2278, 7, 12, 0, 0, 2278, 2279, 7, 23, 0, 0, 2279, 2280, 7, 2, 0, 0, 2280, 2281, 7, 3, 0, 0, 2281, 2282, 7, 4, 0, 0, 2282, 440, 1, 0, 0, 0, 2283, 2284, 7, 7, 0, 0, 2284, 2285, 7, 3, 0, 0, 2285, 2286, 7, 23, 0, 0, 2286, 2287, 5, 95, 0, 0, 2287, 2288, 7, 10, 0, 0, 2288, 2289, 7, 12, 0, 0, 2289, 2290, 5, 95, 0, 0, 2290, 2291, 7, 13, 0, 0, 2291, 2292, 7, 10, 0, 0, 2292, 2293, 7, 15, 0, 0, 2293, 2294, 7, 16, 0, 0, 2294, 2295, 7, 6, 0, 0, 2295, 442, 1, 0, 0, 0, 2296, 2297, 7, 7, 0, 0, 2297, 2298, 7, 3, 0, 0, 2298, 2299, 7, 23, 0, 0, 2299, 2300, 5, 95, 0, 0, 2300, 2301, 7, 10, 0, 0, 2301, 2302, 7, 12, 0, 0, 2302, 2303, 5, 95, 0, 0, 2303, 2304, 7, 11, 0, 0, 2304, 2305, 7, 2, 0, 0, 2305, 2306, 7, 2, 0, 0, 2306, 2307, 7, 22, 0, 0, 2307, 444, 1, 0, 0, 0, 2308, 2309, 7, 2, 0, 0, 2309, 2310, 7, 21, 0, 0, 2310, 2311, 7, 16, 0, 0, 2311, 2312, 7, 4, 0, 0, 2312, 2313, 7, 3, 0, 0, 2313, 2314, 7, 5, 0, 0, 2314, 2315, 7, 16, 0, 0, 2315, 446, 1, 0, 0, 0, 2316, 2317, 7, 12, 0, 0, 2317, 2318, 7, 4, 0, 0, 2318, 2319, 7, 10, 0, 0, 2319, 2320, 7, 13, 0, 0, 2320, 2321, 5, 95, 0, 0, 2321, 2322, 7, 7, 0, 0, 2322, 2323, 7, 3, 0, 0, 2323, 2324, 7, 23, 0, 0, 2324, 2325, 7, 1, 0, 0, 2325, 448, 1, 0, 0, 0, 2326, 2327, 7, 12, 0, 0, 2327, 2328, 7, 4, 0, 0, 2328, 2329, 7, 10, 0, 0, 2329, 2330, 7, 13, 0, 0, 2330, 2331, 5, 95, 0, 0, 2331, 2332, 7, 17, 0, 0, 2332, 2333, 7, 15, 0, 0, 2333, 2334, 7, 8, 0, 0, 2334, 2335, 7, 21, 0, 0, 2335, 2336, 7, 16, 0, 0, 2336, 2337, 7, 8, 0, 0, 2337, 2338, 7, 13, 0, 0, 2338, 2339, 7, 2, 0, 0, 2339, 450, 1, 0, 0, 0, 2340, 2341, 7, 20, 0, 0, 2341, 2342, 7, 2, 0, 0, 2342, 2343, 7, 16, 0, 0, 2343, 2344, 5, 95, 0, 0, 2344, 2345, 7, 12, 0, 0, 2345, 2346, 7, 10, 0, 0, 2346, 2347, 7, 4, 0, 0, 2347, 2348, 7, 13, 0, 0, 2348, 2349, 7, 3, 0, 0, 2349, 2350, 7, 16, 0, 0, 2350, 452, 1, 0, 0, 0, 2351, 2352, 7, 14, 0, 0, 2352, 2353, 7, 3, 0, 0, 2353, 2354, 7, 1, 0, 0, 2354, 2355, 7, 16, 0, 0, 2355, 2356, 5, 95, 0, 0, 2356, 2357, 7, 7, 0, 0, 2357, 2358, 7, 3, 0, 0, 2358, 2359, 7, 23, 0, 0, 2359, 454, 1, 0, 0, 0, 2360, 2361, 7, 14, 0, 0, 2361, 2362, 7, 10, 0, 0, 2362, 2363, 7, 5, 0, 0, 2363, 2364, 7, 3, 0, 0, 2364, 2365, 7, 14, 0, 0, 2365, 2366, 7, 16, 0, 0, 2366, 2367, 7, 8, 0, 0, 2367, 2368, 7, 13, 0, 0, 2368, 2369, 7, 2, 0, 0, 2369, 456, 1, 0, 0, 0, 2370, 2371, 7, 14, 0, 0, 2371, 2372, 7, 10, 0, 0, 2372, 2373, 7, 5, 0, 0, 2373, 2374, 7, 3, 0, 0, 2374, 2375, 7, 14, 0, 0, 2375, 2376, 7, 16, 0, 0, 2376, 2377, 7, 8, 0, 0, 2377, 2378, 7, 13, 0, 0, 2378, 2379, 7, 2, 0, 0, 2379, 2380, 7, 1, 0, 0, 2380, 2381, 7, 16, 0, 0, 2381, 2382, 7, 3, 0, 0, 2382, 2383, 7, 13, 0, 0, 2383, 2384, 7, 18, 0, 0, 2384, 458, 1, 0, 0, 0, 2385, 2386, 7, 13, 0, 0, 2386, 2387, 7, 3, 0, 0, 2387, 2388, 7, 22, 0, 0, 2388, 2389, 7, 2, 0, 0, 2389, 2390, 7, 7, 0, 0, 2390, 2391, 7, 3, 0, 0, 2391, 2392, 7, 16, 0, 0, 2392, 2393, 7, 2, 0, 0, 2393, 460, 1, 0, 0, 0, 2394, 2395, 7, 13, 0, 0, 2395, 2396, 7, 3, 0, 0, 2396, 2397, 7, 22, 0, 0, 2397, 2398, 7, 2, 0, 0, 2398, 2399, 7, 16, 0, 0, 2399, 2400, 7, 8, 0, 0, 2400, 2401, 7, 13, 0, 0, 2401, 2402, 7, 2, 0, 0, 2402, 462, 1, 0, 0, 0, 2403, 2404, 7, 13, 0, 0, 2404, 2405, 7, 10, 0, 0, 2405, 2406, 7, 15, 0, 0, 2406, 2407, 7, 16, 0, 0, 2407, 2408, 7, 6, 0, 0, 2408, 2409, 7, 15, 0, 0, 2409, 2410, 7, 3, 0, 0, 2410, 2411, 7, 13, 0, 0, 2411, 2412, 7, 2, 0, 0, 2412, 464, 1, 0, 0, 0, 2413, 2414, 7, 15, 0, 0, 2414, 2415, 7, 10, 0, 0, 2415, 2416, 7, 11, 0, 0, 2416, 466, 1, 0, 0, 0, 2417, 2418, 7, 18, 0, 0, 2418, 2419, 7, 2, 0, 0, 2419, 2420, 7, 4, 0, 0, 2420, 2421, 7, 8, 0, 0, 2421, 2422, 7, 10, 0, 0, 2422, 2423, 7, 7, 0, 0, 2423, 2424, 5, 95, 0, 0, 2424, 2425, 7, 3, 0, 0, 2425, 2426, 7, 7, 0, 0, 2426, 2427, 7, 7, 0, 0, 2427, 468, 1, 0, 0, 0, 2428, 2429, 7, 18, 0, 0, 2429, 2430, 7, 2, 0, 0, 2430, 2431, 7, 4, 0, 0, 2431, 2432, 7, 8, 0, 0, 2432, 2433, 7, 10, 0, 0, 2433, 2434, 7, 7, 0, 0, 2434, 2435, 5, 95, 0, 0, 2435, 2436, 7, 7, 0, 0, 2436, 2437, 7, 8, 0, 0, 2437, 2438, 7, 12, 0, 0, 2438, 2439, 7, 12, 0, 0, 2439, 470, 1, 0, 0, 0, 2440, 2441, 7, 1, 0, 0, 2441, 2442, 7, 2, 0, 0, 2442, 2443, 7, 5, 0, 0, 2443, 2444, 5, 95, 0, 0, 2444, 2445, 7, 16, 0, 0, 2445, 2446, 7, 10, 0, 0, 2446, 2447, 5, 95, 0, 0, 2447, 2448, 7, 16, 0, 0, 2448, 2449, 7, 8, 0, 0, 2449, 2450, 7, 13, 0, 0, 2450, 2451, 7, 2, 0, 0, 2451, 472, 1, 0, 0, 0, 2452, 2453, 7, 1, 0, 0, 2453, 2454, 7, 16, 0, 0, 2454, 2455, 7, 4, 0, 0, 2455, 2456, 5, 95, 0, 0, 2456, 2457, 7, 16, 0, 0, 2457, 2458, 7, 10, 0, 0, 2458, 2459, 5, 95, 0, 0, 2459, 2460, 7, 7, 0, 0, 2460, 2461, 7, 3, 0, 0, 2461, 2462, 7, 16, 0, 0, 2462, 2463, 7, 2, 0, 0, 2463, 474, 1, 0, 0, 0, 2464, 2465, 7, 1, 0, 0, 2465, 2466, 7, 17, 0, 0, 2466, 2467, 7, 9, 0, 0, 2467, 2468, 7, 7, 0, 0, 2468, 2469, 7, 3, 0, 0, 2469, 2470, 7, 16, 0, 0, 2470, 2471, 7, 2, 0, 0, 2471, 476, 1, 0, 0, 0, 2472, 2473, 7, 1, 0, 0, 2473, 2474, 7, 17, 0, 0, 2474, 2475, 7, 9, 0, 0, 2475, 2476, 7, 16, 0, 0, 2476, 2477, 7, 8, 0, 0, 2477, 2478, 7, 13, 0, 0, 2478, 2479, 7, 2, 0, 0, 2479, 478, 1, 0, 0, 0, 2480, 2481, 7, 1, 0, 0, 2481, 2482, 7, 23, 0, 0, 2482, 2483, 7, 1, 0, 0, 2483, 2484, 7, 7, 0, 0, 2484, 2485, 7, 3, 0, 0, 2485, 2486, 7, 16, 0, 0, 2486, 2487, 7, 2, 0, 0, 2487, 480, 1, 0, 0, 0, 2488, 2489, 7, 16, 0, 0, 2489, 2490, 7, 8, 0, 0, 2490, 2491, 7, 13, 0, 0, 2491, 2492, 7, 2, 0, 0, 2492, 482, 1, 0, 0, 0, 2493, 2494, 7, 16, 0, 0, 2494, 2495, 7, 8, 0, 0, 2495, 2496, 7, 13, 0, 0, 2496, 2497, 7, 2, 0, 0, 2497, 2498, 7, 7, 0, 0, 2498, 2499, 7, 8, 0, 0, 2499, 2500, 7, 12, 0, 0, 2500, 2501, 7, 12, 0, 0, 2501, 484, 1, 0, 0, 0, 2502, 2503, 7, 16, 0, 0, 2503, 2504, 7, 8, 0, 0, 2504, 2505, 7, 13, 0, 0, 2505, 2506, 7, 2, 0, 0, 2506, 2507, 7, 1, 0, 0, 2507, 2508, 7, 16, 0, 0, 2508, 2509, 7, 3, 0, 0, 2509, 2510, 7, 13, 0, 0, 2510, 2511, 7, 18, 0, 0, 2511, 486, 1, 0, 0, 0, 2512, 2513, 7, 16, 0, 0, 2513, 2514, 7, 8, 0, 0, 2514, 2515, 7, 13, 0, 0, 2515, 2516, 7, 2, 0, 0, 2516, 2517, 7, 1, 0, 0, 2517, 2518, 7, 16, 0, 0, 2518, 2519, 7, 3, 0, 0, 2519, 2520, 7, 13, 0, 0, 2520, 2521, 7, 18, 0, 0, 2521, 2522, 7, 3, 0, 0, 2522, 2523, 7, 7, 0, 0, 2523, 2524, 7, 7, 0, 0, 2524, 488, 1, 0, 0, 0, 2525, 2526, 7, 16, 0, 0, 2526, 2527, 7, 8, 0, 0, 2527, 2528, 7, 13, 0, 0, 2528, 2529, 7, 2, 0, 0, 2529, 2530, 7, 1, 0, 0, 2530, 2531, 7, 16, 0, 0, 2531, 2532, 7, 3, 0, 0, 2532, 2533, 7, 13, 0, 0, 2533, 2534, 7, 18, 0, 0, 2534, 2535, 7, 7, 0, 0, 2535, 2536, 7, 8, 0, 0, 2536, 2537, 7, 12, 0, 0, 2537, 2538, 7, 12, 0, 0, 2538, 490, 1, 0, 0, 0, 2539, 2540, 7, 16, 0, 0, 2540, 2541, 7, 8, 0, 0, 2541, 2542, 7, 13, 0, 0, 2542, 2543, 7, 2, 0, 0, 2543, 2544, 5, 95, 0, 0, 2544, 2545, 7, 12, 0, 0, 2545, 2546, 7, 10, 0, 0, 2546, 2547, 7, 4, 0, 0, 2547, 2548, 7, 13, 0, 0, 2548, 2549, 7, 3, 0, 0, 2549, 2550, 7, 16, 0, 0, 2550, 492, 1, 0, 0, 0, 2551, 2552, 7, 16, 0, 0, 2552, 2553, 7, 8, 0, 0, 2553, 2554, 7, 13, 0, 0, 2554, 2555, 7, 2, 0, 0, 2555, 2556, 5, 95, 0, 0, 2556, 2557, 7, 16, 0, 0, 2557, 2558, 7, 10, 0, 0, 2558, 2559, 5, 95, 0, 0, 2559, 2560, 7, 1, 0, 0, 2560, 2561, 7, 2, 0, 0, 2561, 2562, 7, 5, 0, 0, 2562, 494, 1, 0, 0, 0, 2563, 2564, 7, 16, 0, 0, 2564, 2565, 7, 10, 0, 0, 2565, 2566, 5, 95, 0, 0, 2566, 2567, 7, 7, 0, 0, 2567, 2568, 7, 3, 0, 0, 2568, 2569, 7, 23, 0, 0, 2569, 2570, 7, 1, 0, 0, 2570, 496, 1, 0, 0, 0, 2571, 2572, 7, 16, 0, 0, 2572, 2573, 7, 10, 0, 0, 2573, 2574, 5, 95, 0, 0, 2574, 2575, 7, 1, 0, 0, 2575, 2576, 7, 2, 0, 0, 2576, 2577, 7, 5, 0, 0, 2577, 2578, 7, 10, 0, 0, 2578, 2579, 7, 15, 0, 0, 2579, 2580, 7, 7, 0, 0, 2580, 2581, 7, 1, 0, 0, 2581, 498, 1, 0, 0, 0, 2582, 2583, 7, 17, 0, 0, 2583, 2584, 7, 15, 0, 0, 2584, 2585, 7, 8, 0, 0, 2585, 2586, 7, 21, 0, 0, 2586, 2587, 5, 95, 0, 0, 2587, 2588, 7, 16, 0, 0, 2588, 2589, 7, 8, 0, 0, 2589, 2590, 7, 13, 0, 0, 2590, 2591, 7, 2, 0, 0, 2591, 2592, 7, 1, 0, 0, 2592, 2593, 7, 16, 0, 0, 2593, 2594, 7, 3, 0, 0, 2594, 2595, 7, 13, 0, 0, 2595, 2596, 7, 18, 0, 0, 2596, 500, 1, 0, 0, 0, 2597, 2598, 7, 17, 0, 0, 2598, 2599, 7, 16, 0, 0, 2599, 2600, 7, 5, 0, 0, 2600, 2601, 5, 95, 0, 0, 2601, 2602, 7, 7, 0, 0, 2602, 2603, 7, 3, 0, 0, 2603, 2604, 7, 16, 0, 0, 2604, 2605, 7, 2, 0, 0, 2605, 502, 1, 0, 0, 0, 2606, 2607, 7, 17, 0, 0, 2607, 2608, 7, 16, 0, 0, 2608, 2609, 7, 5, 0, 0, 2609, 2610, 5, 95, 0, 0, 2610, 2611, 7, 16, 0, 0, 2611, 2612, 7, 8, 0, 0, 2612, 2613, 7, 13, 0, 0, 2613, 2614, 7, 2, 0, 0, 2614, 504, 1, 0, 0, 0, 2615, 2616, 7, 17, 0, 0, 2616, 2617, 7, 16, 0, 0, 2617, 2618, 7, 5, 0, 0, 2618, 2619, 5, 95, 0, 0, 2619, 2620, 7, 16, 0, 0, 2620, 2621, 7, 8, 0, 0, 2621, 2622, 7, 13, 0, 0, 2622, 2623, 7, 2, 0, 0, 2623, 2624, 7, 1, 0, 0, 2624, 2625, 7, 16, 0, 0, 2625, 2626, 7, 3, 0, 0, 2626, 2627, 7, 13, 0, 0, 2627, 2628, 7, 18, 0, 0, 2628, 506, 1, 0, 0, 0, 2629, 2630, 7, 11, 0, 0, 2630, 2631, 7, 2, 0, 0, 2631, 2632, 7, 2, 0, 0, 2632, 2633, 7, 22, 0, 0, 2633, 2634, 7, 7, 0, 0, 2634, 2635, 7, 3, 0, 0, 2635, 2636, 7, 23, 0, 0, 2636, 508, 1, 0, 0, 0, 2637, 2638, 7, 23, 0, 0, 2638, 2639, 7, 2, 0, 0, 2639, 2640, 7, 3, 0, 0, 2640, 2641, 7, 4, 0, 0, 2641, 2642, 7, 11, 0, 0, 2642, 2643, 7, 2, 0, 0, 2643, 2644, 7, 2, 0, 0, 2644, 2645, 7, 22, 0, 0, 2645, 510, 1, 0, 0, 0, 2646, 2647, 7, 1, 0, 0, 2647, 2648, 7, 17, 0, 0, 2648, 2649, 7, 9, 0, 0, 2649, 2650, 7, 1, 0, 0, 2650, 2651, 7, 16, 0, 0, 2651, 2652, 7, 4, 0, 0, 2652, 512, 1, 0, 0, 0, 2653, 2654, 7, 1, 0, 0, 2654, 2655, 7, 17, 0, 0, 2655, 2656, 7, 9, 0, 0, 2656, 2657, 7, 1, 0, 0, 2657, 2658, 7, 16, 0, 0, 2658, 2659, 7, 4, 0, 0, 2659, 2660, 7, 8, 0, 0, 2660, 2661, 7, 15, 0, 0, 2661, 2662, 7, 20, 0, 0, 2662, 514, 1, 0, 0, 0, 2663, 2664, 7, 14, 0, 0, 2664, 2665, 7, 16, 0, 0, 2665, 2666, 7, 4, 0, 0, 2666, 2667, 7, 8, 0, 0, 2667, 2668, 7, 13, 0, 0, 2668, 516, 1, 0, 0, 0, 2669, 2670, 7, 4, 0, 0, 2670, 2671, 7, 16, 0, 0, 2671, 2672, 7, 4, 0, 0, 2672, 2673, 7, 8, 0, 0, 2673, 2674, 7, 13, 0, 0, 2674, 518, 1, 0, 0, 0, 2675, 2676, 7, 16, 0, 0, 2676, 2677, 7, 4, 0, 0, 2677, 2678, 7, 8, 0, 0, 2678, 2679, 7, 13, 0, 0, 2679, 520, 1, 0, 0, 0, 2680, 2681, 7, 16, 0, 0, 2681, 2682, 7, 10, 0, 0, 2682, 522, 1, 0, 0, 0, 2683, 2684, 7, 14, 0, 0, 2684, 2685, 7, 10, 0, 0, 2685, 2686, 7, 11, 0, 0, 2686, 2687, 7, 2, 0, 0, 2687, 2688, 7, 4, 0, 0, 2688, 524, 1, 0, 0, 0, 2689, 2690, 7, 17, 0, 0, 2690, 2691, 7, 18, 0, 0, 2691, 2692, 7, 18, 0, 0, 2692, 2693, 7, 2, 0, 0, 2693, 2694, 7, 4, 0, 0, 2694, 526, 1, 0, 0, 0, 2695, 2696, 7, 5, 0, 0, 2696, 2697, 7, 10, 0, 0, 2697, 2698, 7, 15, 0, 0, 2698, 2699, 7, 5, 0, 0, 2699, 2700, 7, 3, 0, 0, 2700, 2701, 7, 16, 0, 0, 2701, 528, 1, 0, 0, 0, 2702, 2703, 7, 5, 0, 0, 2703, 2704, 7, 10, 0, 0, 2704, 2705, 7, 15, 0, 0, 2705, 2706, 7, 5, 0, 0, 2706, 2707, 7, 3, 0, 0, 2707, 2708, 7, 16, 0, 0, 2708, 2709, 5, 95, 0, 0, 2709, 2710, 7, 11, 0, 0, 2710, 2711, 7, 1, 0, 0, 2711, 530, 1, 0, 0, 0, 2712, 2713, 7, 14, 0, 0, 2713, 2714, 7, 2, 0, 0, 2714, 2715, 7, 15, 0, 0, 2715, 2716, 7, 20, 0, 0, 2716, 2717, 7, 16, 0, 0, 2717, 2718, 7, 6, 0, 0, 2718, 532, 1, 0, 0, 0, 2719, 2720, 7, 1, 0, 0, 2720, 2721, 7, 16, 0, 0, 2721, 2722, 7, 4, 0, 0, 2722, 2723, 7, 5, 0, 0, 2723, 2724, 7, 13, 0, 0, 2724, 2725, 7, 18, 0, 0, 2725, 534, 1, 0, 0, 0, 2726, 2727, 7, 4, 0, 0, 2727, 2728, 7, 8, 0, 0, 2728, 2729, 7, 20, 0, 0, 2729, 2730, 7, 6, 0, 0, 2730, 2731, 7, 16, 0, 0, 2731, 536, 1, 0, 0, 0, 2732, 2733, 7, 14, 0, 0, 2733, 2734, 7, 2, 0, 0, 2734, 2735, 7, 12, 0, 0, 2735, 2736, 7, 16, 0, 0, 2736, 538, 1, 0, 0, 0, 2737, 2738, 7, 3, 0, 0, 2738, 2739, 7, 1, 0, 0, 2739, 2740, 7, 5, 0, 0, 2740, 2741, 7, 8, 0, 0, 2741, 2742, 7, 8, 0, 0, 2742, 540, 1, 0, 0, 0, 2743, 2744, 7, 14, 0, 0, 2744, 2745, 7, 10, 0, 0, 2745, 2746, 7, 5, 0, 0, 2746, 2747, 7, 3, 0, 0, 2747, 2748, 7, 16, 0, 0, 2748, 2749, 7, 2, 0, 0, 2749, 542, 1, 0, 0, 0, 2750, 2751, 7, 4, 0, 0, 2751, 2752, 7, 2, 0, 0, 2752, 2753, 7, 18, 0, 0, 2753, 2754, 7, 14, 0, 0, 2754, 2755, 7, 3, 0, 0, 2755, 2756, 7, 5, 0, 0, 2756, 2757, 7, 2, 0, 0, 2757, 544, 1, 0, 0, 0, 2758, 2759, 7, 4, 0, 0, 2759, 2760, 7, 2, 0, 0, 2760, 2761, 7, 19, 0, 0, 2761, 2762, 7, 2, 0, 0, 2762, 2763, 7, 4, 0, 0, 2763, 2764, 7, 1, 0, 0, 2764, 2765, 7, 2, 0, 0, 2765, 546, 1, 0, 0, 0, 2766, 2767, 7, 5, 0, 0, 2767, 2768, 7, 3, 0, 0, 2768, 2769, 7, 1, 0, 0, 2769, 2770, 7, 16, 0, 0, 2770, 548, 1, 0, 0, 0, 2771, 2772, 7, 14, 0, 0, 2772, 2773, 7, 8, 0, 0, 2773, 2774, 7, 22, 0, 0, 2774, 2775, 7, 2, 0, 0, 2775, 550, 1, 0, 0, 0, 2776, 2777, 7, 8, 0, 0, 2777, 2778, 7, 1, 0, 0, 2778, 2779, 7, 15, 0, 0, 2779, 2780, 7, 17, 0, 0, 2780, 2781, 7, 14, 0, 0, 2781, 2782, 7, 14, 0, 0, 2782, 552, 1, 0, 0, 0, 2783, 2784, 7, 8, 0, 0, 2784, 2785, 7, 1, 0, 0, 2785, 2786, 7, 15, 0, 0, 2786, 2787, 7, 10, 0, 0, 2787, 2788, 7, 16, 0, 0, 2788, 2789, 7, 15, 0, 0, 2789, 2790, 7, 17, 0, 0, 2790, 2791, 7, 14, 0, 0, 2791, 2792, 7, 14, 0, 0, 2792, 554, 1, 0, 0, 0, 2793, 2794, 7, 8, 0, 0, 2794, 2795, 7, 12, 0, 0, 2795, 2796, 7, 15, 0, 0, 2796, 2797, 7, 17, 0, 0, 2797, 2798, 7, 14, 0, 0, 2798, 2799, 7, 14, 0, 0, 2799, 556, 1, 0, 0, 0, 2800, 2801, 7, 15, 0, 0, 2801, 2802, 7, 17, 0, 0, 2802, 2803, 7, 14, 0, 0, 2803, 2804, 7, 14, 0, 0, 2804, 2805, 7, 8, 0, 0, 2805, 2806, 7, 12, 0, 0, 2806, 558, 1, 0, 0, 0, 2807, 2808, 7, 8, 0, 0, 2808, 2809, 7, 12, 0, 0, 2809, 560, 1, 0, 0, 0, 2810, 2811, 7, 16, 0, 0, 2811, 2812, 7, 23, 0, 0, 2812, 2813, 7, 18, 0, 0, 2813, 2814, 7, 2, 0, 0, 2814, 2815, 7, 10, 0, 0, 2815, 2816, 7, 12, 0, 0, 2816, 562, 1, 0, 0, 0, 2817, 2818, 7, 13, 0, 0, 2818, 2819, 7, 3, 0, 0, 2819, 2820, 7, 16, 0, 0, 2820, 2821, 7, 5, 0, 0, 2821, 2822, 7, 6, 0, 0, 2822, 564, 1, 0, 0, 0, 2823, 2824, 7, 13, 0, 0, 2824, 2825, 7, 3, 0, 0, 2825, 2826, 7, 16, 0, 0, 2826, 2827, 7, 5, 0, 0, 2827, 2828, 7, 6, 0, 0, 2828, 2829, 5, 95, 0, 0, 2829, 2830, 7, 18, 0, 0, 2830, 2831, 7, 6, 0, 0, 2831, 2832, 7, 4, 0, 0, 2832, 2833, 7, 3, 0, 0, 2833, 2834, 7, 1, 0, 0, 2834, 2835, 7, 2, 0, 0, 2835, 566, 1, 0, 0, 0, 2836, 2837, 7, 13, 0, 0, 2837, 2838, 7, 3, 0, 0, 2838, 2839, 7, 16, 0, 0, 2839, 2840, 7, 5, 0, 0, 2840, 2841, 7, 6, 0, 0, 2841, 2842, 5, 95, 0, 0, 2842, 2843, 7, 18, 0, 0, 2843, 2844, 7, 6, 0, 0, 2844, 2845, 7, 4, 0, 0, 2845, 2846, 7, 3, 0, 0, 2846, 2847, 7, 1, 0, 0, 2847, 2848, 7, 2, 0, 0, 2848, 2849, 5, 95, 0, 0, 2849, 2850, 7, 18, 0, 0, 2850, 2851, 7, 4, 0, 0, 2851, 2852, 7, 2, 0, 0, 2852, 2853, 7, 12, 0, 0, 2853, 2854, 7, 8, 0, 0, 2854, 2855, 7, 21, 0, 0, 2855, 568, 1, 0, 0, 0, 2856, 2857, 7, 13, 0, 0, 2857, 2858, 7, 3, 0, 0, 2858, 2859, 7, 16, 0, 0, 2859, 2860, 7, 5, 0, 0, 2860, 2861, 7, 6, 0, 0, 2861, 2862, 5, 95, 0, 0, 2862, 2863, 7, 9, 0, 0, 2863, 2864, 7, 10, 0, 0, 2864, 2865, 7, 10, 0, 0, 2865, 2866, 7, 14, 0, 0, 2866, 2867, 5, 95, 0, 0, 2867, 2868, 7, 18, 0, 0, 2868, 2869, 7, 4, 0, 0, 2869, 2870, 7, 2, 0, 0, 2870, 2871, 7, 12, 0, 0, 2871, 2872, 7, 8, 0, 0, 2872, 2873, 7, 21, 0, 0, 2873, 570, 1, 0, 0, 0, 2874, 2875, 7, 1, 0, 0, 2875, 2876, 7, 8, 0, 0, 2876, 2877, 7, 13, 0, 0, 2877, 2878, 7, 18, 0, 0, 2878, 2879, 7, 14, 0, 0, 2879, 2880, 7, 2, 0, 0, 2880, 2881, 5, 95, 0, 0, 2881, 2882, 7, 25, 0, 0, 2882, 2883, 7, 17, 0, 0, 2883, 2884, 7, 2, 0, 0, 2884, 2885, 7, 4, 0, 0, 2885, 2886, 7, 23, 0, 0, 2886, 2887, 5, 95, 0, 0, 2887, 2888, 7, 1, 0, 0, 2888, 2889, 7, 16, 0, 0, 2889, 2890, 7, 4, 0, 0, 2890, 2891, 7, 8, 0, 0, 2891, 2892, 7, 15, 0, 0, 2892, 2893, 7, 20, 0, 0, 2893, 572, 1, 0, 0, 0, 2894, 2895, 7, 13, 0, 0, 2895, 2896, 7, 17, 0, 0, 2896, 2897, 7, 14, 0, 0, 2897, 2898, 7, 16, 0, 0, 2898, 2899, 7, 8, 0, 0, 2899, 2900, 5, 95, 0, 0, 2900, 2901, 7, 13, 0, 0, 2901, 2902, 7, 3, 0, 0, 2902, 2903, 7, 16, 0, 0, 2903, 2904, 7, 5, 0, 0, 2904, 2905, 7, 6, 0, 0, 2905, 574, 1, 0, 0, 0, 2906, 2907, 7, 25, 0, 0, 2907, 2908, 7, 17, 0, 0, 2908, 2909, 7, 2, 0, 0, 2909, 2910, 7, 4, 0, 0, 2910, 2911, 7, 23, 0, 0, 2911, 2912, 5, 95, 0, 0, 2912, 2913, 7, 1, 0, 0, 2913, 2914, 7, 16, 0, 0, 2914, 2915, 7, 4, 0, 0, 2915, 2916, 7, 8, 0, 0, 2916, 2917, 7, 15, 0, 0, 2917, 2918, 7, 20, 0, 0, 2918, 576, 1, 0, 0, 0, 2919, 2920, 7, 3, 0, 0, 2920, 2921, 7, 14, 0, 0, 2921, 2922, 7, 14, 0, 0, 2922, 2923, 7, 10, 0, 0, 2923, 2924, 7, 11, 0, 0, 2924, 2925, 5, 95, 0, 0, 2925, 2926, 7, 14, 0, 0, 2926, 2927, 7, 2, 0, 0, 2927, 2928, 7, 3, 0, 0, 2928, 2929, 7, 7, 0, 0, 2929, 2930, 7, 8, 0, 0, 2930, 2931, 7, 15, 0, 0, 2931, 2932, 7, 20, 0, 0, 2932, 2933, 5, 95, 0, 0, 2933, 2934, 7, 11, 0, 0, 2934, 2935, 7, 8, 0, 0, 2935, 2936, 7, 14, 0, 0, 2936, 2937, 7, 7, 0, 0, 2937, 2938, 7, 5, 0, 0, 2938, 2939, 7, 3, 0, 0, 2939, 2940, 7, 4, 0, 0, 2940, 2941, 7, 7, 0, 0, 2941, 578, 1, 0, 0, 0, 2942, 2943, 7, 3, 0, 0, 2943, 2944, 7, 15, 0, 0, 2944, 2945, 7, 3, 0, 0, 2945, 2946, 7, 14, 0, 0, 2946, 2947, 7, 23, 0, 0, 2947, 2948, 7, 24, 0, 0, 2948, 2949, 7, 2, 0, 0, 2949, 2950, 5, 95, 0, 0, 2950, 2951, 7, 11, 0, 0, 2951, 2952, 7, 8, 0, 0, 2952, 2953, 7, 14, 0, 0, 2953, 2954, 7, 7, 0, 0, 2954, 2955, 7, 5, 0, 0, 2955, 2956, 7, 3, 0, 0, 2956, 2957, 7, 4, 0, 0, 2957, 2958, 7, 7, 0, 0, 2958, 580, 1, 0, 0, 0, 2959, 2960, 7, 3, 0, 0, 2960, 2961, 7, 15, 0, 0, 2961, 2962, 7, 3, 0, 0, 2962, 2963, 7, 14, 0, 0, 2963, 2964, 7, 23, 0, 0, 2964, 2965, 7, 24, 0, 0, 2965, 2966, 7, 2, 0, 0, 2966, 2967, 7, 4, 0, 0, 2967, 582, 1, 0, 0, 0, 2968, 2969, 7, 3, 0, 0, 2969, 2970, 7, 17, 0, 0, 2970, 2971, 7, 16, 0, 0, 2971, 2972, 7, 10, 0, 0, 2972, 2973, 5, 95, 0, 0, 2973, 2974, 7, 20, 0, 0, 2974, 2975, 7, 2, 0, 0, 2975, 2976, 7, 15, 0, 0, 2976, 2977, 7, 2, 0, 0, 2977, 2978, 7, 4, 0, 0, 2978, 2979, 7, 3, 0, 0, 2979, 2980, 7, 16, 0, 0, 2980, 2981, 7, 2, 0, 0, 2981, 2982, 5, 95, 0, 0, 2982, 2983, 7, 1, 0, 0, 2983, 2984, 7, 23, 0, 0, 2984, 2985, 7, 15, 0, 0, 2985, 2986, 7, 10, 0, 0, 2986, 2987, 7, 15, 0, 0, 2987, 2988, 7, 23, 0, 0, 2988, 2989, 7, 13, 0, 0, 2989, 2990, 7, 1, 0, 0, 2990, 2991, 5, 95, 0, 0, 2991, 2992, 7, 18, 0, 0, 2992, 2993, 7, 6, 0, 0, 2993, 2994, 7, 4, 0, 0, 2994, 2995, 7, 3, 0, 0, 2995, 2996, 7, 1, 0, 0, 2996, 2997, 7, 2, 0, 0, 2997, 2998, 5, 95, 0, 0, 2998, 2999, 7, 25, 0, 0, 2999, 3000, 7, 17, 0, 0, 3000, 3001, 7, 2, 0, 0, 3001, 3002, 7, 4, 0, 0, 3002, 3003, 7, 23, 0, 0, 3003, 584, 1, 0, 0, 0, 3004, 3005, 7, 9, 0, 0, 3005, 3006, 7, 10, 0, 0, 3006, 3007, 7, 10, 0, 0, 3007, 3008, 7, 1, 0, 0, 3008, 3009, 7, 16, 0, 0, 3009, 586, 1, 0, 0, 0, 3010, 3011, 7, 5, 0, 0, 3011, 3012, 7, 17, 0, 0, 3012, 3013, 7, 16, 0, 0, 3013, 3014, 7, 10, 0, 0, 3014, 3015, 7, 12, 0, 0, 3015, 3016, 7, 12, 0, 0, 3016, 3017, 5, 95, 0, 0, 3017, 3018, 7, 12, 0, 0, 3018, 3019, 7, 4, 0, 0, 3019, 3020, 7, 2, 0, 0, 3020, 3021, 7, 25, 0, 0, 3021, 3022, 7, 17, 0, 0, 3022, 3023, 7, 2, 0, 0, 3023, 3024, 7, 15, 0, 0, 3024, 3025, 7, 5, 0, 0, 3025, 3026, 7, 23, 0, 0, 3026, 588, 1, 0, 0, 0, 3027, 3028, 7, 7, 0, 0, 3028, 3029, 7, 2, 0, 0, 3029, 3030, 7, 12, 0, 0, 3030, 3031, 7, 3, 0, 0, 3031, 3032, 7, 17, 0, 0, 3032, 3033, 7, 14, 0, 0, 3033, 3034, 7, 16, 0, 0, 3034, 3035, 5, 95, 0, 0, 3035, 3036, 7, 12, 0, 0, 3036, 3037, 7, 8, 0, 0, 3037, 3038, 7, 2, 0, 0, 3038, 3039, 7, 14, 0, 0, 3039, 3040, 7, 7, 0, 0, 3040, 590, 1, 0, 0, 0, 3041, 3042, 7, 7, 0, 0, 3042, 3043, 7, 2, 0, 0, 3043, 3044, 7, 12, 0, 0, 3044, 3045, 7, 3, 0, 0, 3045, 3046, 7, 17, 0, 0, 3046, 3047, 7, 14, 0, 0, 3047, 3048, 7, 16, 0, 0, 3048, 3049, 5, 95, 0, 0, 3049, 3050, 7, 10, 0, 0, 3050, 3051, 7, 18, 0, 0, 3051, 3052, 7, 2, 0, 0, 3052, 3053, 7, 4, 0, 0, 3053, 3054, 7, 3, 0, 0, 3054, 3055, 7, 16, 0, 0, 3055, 3056, 7, 10, 0, 0, 3056, 3057, 7, 4, 0, 0, 3057, 592, 1, 0, 0, 0, 3058, 3059, 7, 2, 0, 0, 3059, 3060, 7, 15, 0, 0, 3060, 3061, 7, 3, 0, 0, 3061, 3062, 7, 9, 0, 0, 3062, 3063, 7, 14, 0, 0, 3063, 3064, 7, 2, 0, 0, 3064, 3065, 5, 95, 0, 0, 3065, 3066, 7, 18, 0, 0, 3066, 3067, 7, 10, 0, 0, 3067, 3068, 7, 1, 0, 0, 3068, 3069, 7, 8, 0, 0, 3069, 3070, 7, 16, 0, 0, 3070, 3071, 7, 8, 0, 0, 3071, 3072, 7, 10, 0, 0, 3072, 3073, 7, 15, 0, 0, 3073, 3074, 5, 95, 0, 0, 3074, 3075, 7, 8, 0, 0, 3075, 3076, 7, 15, 0, 0, 3076, 3077, 7, 5, 0, 0, 3077, 3078, 7, 4, 0, 0, 3078, 3079, 7, 2, 0, 0, 3079, 3080, 7, 13, 0, 0, 3080, 3081, 7, 2, 0, 0, 3081, 3082, 7, 15, 0, 0, 3082, 3083, 7, 16, 0, 0, 3083, 3084, 7, 1, 0, 0, 3084, 594, 1, 0, 0, 0, 3085, 3086, 7, 2, 0, 0, 3086, 3087, 7, 1, 0, 0, 3087, 3088, 7, 5, 0, 0, 3088, 3089, 7, 3, 0, 0, 3089, 3090, 7, 18, 0, 0, 3090, 3091, 7, 2, 0, 0, 3091, 596, 1, 0, 0, 0, 3092, 3093, 7, 12, 0, 0, 3093, 3094, 7, 14, 0, 0, 3094, 3095, 7, 3, 0, 0, 3095, 3096, 7, 20, 0, 0, 3096, 3097, 7, 1, 0, 0, 3097, 598, 1, 0, 0, 0, 3098, 3099, 7, 12, 0, 0, 3099, 3100, 7, 17, 0, 0, 3100, 3101, 7, 24, 0, 0, 3101, 3102, 7, 24, 0, 0, 3102, 3103, 7, 23, 0, 0, 3103, 3104, 5, 95, 0, 0, 3104, 3105, 7, 13, 0, 0, 3105, 3106, 7, 3, 0, 0, 3106, 3107, 7, 21, 0, 0, 3107, 3108, 5, 95, 0, 0, 3108, 3109, 7, 2, 0, 0, 3109, 3110, 7, 21, 0, 0, 3110, 3111, 7, 18, 0, 0, 3111, 3112, 7, 3, 0, 0, 3112, 3113, 7, 15, 0, 0, 3113, 3114, 7, 1, 0, 0, 3114, 3115, 7, 8, 0, 0, 3115, 3116, 7, 10, 0, 0, 3116, 3117, 7, 15, 0, 0, 3117, 3118, 7, 1, 0, 0, 3118, 600, 1, 0, 0, 0, 3119, 3120, 7, 12, 0, 0, 3120, 3121, 7, 17, 0, 0, 3121, 3122, 7, 24, 0, 0, 3122, 3123, 7, 24, 0, 0, 3123, 3124, 7, 23, 0, 0, 3124, 3125, 5, 95, 0, 0, 3125, 3126, 7, 18, 0, 0, 3126, 3127, 7, 4, 0, 0, 3127, 3128, 7, 2, 0, 0, 3128, 3129, 7, 12, 0, 0, 3129, 3130, 7, 8, 0, 0, 3130, 3131, 7, 21, 0, 0, 3131, 3132, 5, 95, 0, 0, 3132, 3133, 7, 14, 0, 0, 3133, 3134, 7, 2, 0, 0, 3134, 3135, 7, 15, 0, 0, 3135, 3136, 7, 20, 0, 0, 3136, 3137, 7, 16, 0, 0, 3137, 3138, 7, 6, 0, 0, 3138, 602, 1, 0, 0, 0, 3139, 3140, 7, 12, 0, 0, 3140, 3141, 7, 17, 0, 0, 3141, 3142, 7, 24, 0, 0, 3142, 3143, 7, 24, 0, 0, 3143, 3144, 7, 23, 0, 0, 3144, 3145, 5, 95, 0, 0, 3145, 3146, 7, 16, 0, 0, 3146, 3147, 7, 4, 0, 0, 3147, 3148, 7, 3, 0, 0, 3148, 3149, 7, 15, 0, 0, 3149, 3150, 7, 1, 0, 0, 3150, 3151, 7, 18, 0, 0, 3151, 3152, 7, 10, 0, 0, 3152, 3153, 7, 1, 0, 0, 3153, 3154, 7, 8, 0, 0, 3154, 3155, 7, 16, 0, 0, 3155, 3156, 7, 8, 0, 0, 3156, 3157, 7, 10, 0, 0, 3157, 3158, 7, 15, 0, 0, 3158, 3159, 7, 1, 0, 0, 3159, 604, 1, 0, 0, 0, 3160, 3161, 7, 12, 0, 0, 3161, 3162, 7, 17, 0, 0, 3162, 3163, 7, 24, 0, 0, 3163, 3164, 7, 24, 0, 0, 3164, 3165, 7, 23, 0, 0, 3165, 3166, 5, 95, 0, 0, 3166, 3167, 7, 4, 0, 0, 3167, 3168, 7, 2, 0, 0, 3168, 3169, 7, 11, 0, 0, 3169, 3170, 7, 4, 0, 0, 3170, 3171, 7, 8, 0, 0, 3171, 3172, 7, 16, 0, 0, 3172, 3173, 7, 2, 0, 0, 3173, 606, 1, 0, 0, 0, 3174, 3175, 7, 12, 0, 0, 3175, 3176, 7, 17, 0, 0, 3176, 3177, 7, 24, 0, 0, 3177, 3178, 7, 24, 0, 0, 3178, 3179, 7, 8, 0, 0, 3179, 3180, 7, 15, 0, 0, 3180, 3181, 7, 2, 0, 0, 3181, 3182, 7, 1, 0, 0, 3182, 3183, 7, 1, 0, 0, 3183, 608, 1, 0, 0, 0, 3184, 3185, 7, 14, 0, 0, 3185, 3186, 7, 2, 0, 0, 3186, 3187, 7, 15, 0, 0, 3187, 3188, 7, 8, 0, 0, 3188, 3189, 7, 2, 0, 0, 3189, 3190, 7, 15, 0, 0, 3190, 3191, 7, 16, 0, 0, 3191, 610, 1, 0, 0, 0, 3192, 3193, 7, 14, 0, 0, 3193, 3194, 7, 10, 0, 0, 3194, 3195, 7, 11, 0, 0, 3195, 3196, 5, 95, 0, 0, 3196, 3197, 7, 12, 0, 0, 3197, 3198, 7, 4, 0, 0, 3198, 3199, 7, 2, 0, 0, 3199, 3200, 7, 25, 0, 0, 3200, 3201, 5, 95, 0, 0, 3201, 3202, 7, 10, 0, 0, 3202, 3203, 7, 18, 0, 0, 3203, 3204, 7, 2, 0, 0, 3204, 3205, 7, 4, 0, 0, 3205, 3206, 7, 3, 0, 0, 3206, 3207, 7, 16, 0, 0, 3207, 3208, 7, 10, 0, 0, 3208, 3209, 7, 4, 0, 0, 3209, 612, 1, 0, 0, 0, 3210, 3211, 7, 13, 0, 0, 3211, 3212, 7, 3, 0, 0, 3212, 3213, 7, 21, 0, 0, 3213, 3214, 5, 95, 0, 0, 3214, 3215, 7, 7, 0, 0, 3215, 3216, 7, 2, 0, 0, 3216, 3217, 7, 16, 0, 0, 3217, 3218, 7, 2, 0, 0, 3218, 3219, 7, 4, 0, 0, 3219, 3220, 7, 13, 0, 0, 3220, 3221, 7, 8, 0, 0, 3221, 3222, 7, 15, 0, 0, 3222, 3223, 7, 8, 0, 0, 3223, 3224, 7, 24, 0, 0, 3224, 3225, 7, 2, 0, 0, 3225, 3226, 7, 7, 0, 0, 3226, 3227, 5, 95, 0, 0, 3227, 3228, 7, 1, 0, 0, 3228, 3229, 7, 16, 0, 0, 3229, 3230, 7, 3, 0, 0, 3230, 3231, 7, 16, 0, 0, 3231, 3232, 7, 2, 0, 0, 3232, 3233, 7, 1, 0, 0, 3233, 614, 1, 0, 0, 0, 3234, 3235, 7, 13, 0, 0, 3235, 3236, 7, 3, 0, 0, 3236, 3237, 7, 21, 0, 0, 3237, 3238, 5, 95, 0, 0, 3238, 3239, 7, 2, 0, 0, 3239, 3240, 7, 21, 0, 0, 3240, 3241, 7, 18, 0, 0, 3241, 3242, 7, 3, 0, 0, 3242, 3243, 7, 15, 0, 0, 3243, 3244, 7, 1, 0, 0, 3244, 3245, 7, 8, 0, 0, 3245, 3246, 7, 10, 0, 0, 3246, 3247, 7, 15, 0, 0, 3247, 3248, 7, 1, 0, 0, 3248, 616, 1, 0, 0, 0, 3249, 3250, 7, 13, 0, 0, 3250, 3251, 7, 8, 0, 0, 3251, 3252, 7, 15, 0, 0, 3252, 3253, 7, 8, 0, 0, 3253, 3254, 7, 13, 0, 0, 3254, 3255, 7, 17, 0, 0, 3255, 3256, 7, 13, 0, 0, 3256, 3257, 5, 95, 0, 0, 3257, 3258, 7, 1, 0, 0, 3258, 3259, 7, 6, 0, 0, 3259, 3260, 7, 10, 0, 0, 3260, 3261, 7, 17, 0, 0, 3261, 3262, 7, 14, 0, 0, 3262, 3263, 7, 7, 0, 0, 3263, 3264, 5, 95, 0, 0, 3264, 3265, 7, 13, 0, 0, 3265, 3266, 7, 3, 0, 0, 3266, 3267, 7, 16, 0, 0, 3267, 3268, 7, 5, 0, 0, 3268, 3269, 7, 6, 0, 0, 3269, 618, 1, 0, 0, 0, 3270, 3271, 7, 10, 0, 0, 3271, 3272, 7, 18, 0, 0, 3272, 3273, 7, 2, 0, 0, 3273, 3274, 7, 4, 0, 0, 3274, 3275, 7, 3, 0, 0, 3275, 3276, 7, 16, 0, 0, 3276, 3277, 7, 10, 0, 0, 3277, 3278, 7, 4, 0, 0, 3278, 620, 1, 0, 0, 0, 3279, 3280, 7, 18, 0, 0, 3280, 3281, 7, 6, 0, 0, 3281, 3282, 7, 4, 0, 0, 3282, 3283, 7, 3, 0, 0, 3283, 3284, 7, 1, 0, 0, 3284, 3285, 7, 2, 0, 0, 3285, 3286, 5, 95, 0, 0, 3286, 3287, 7, 1, 0, 0, 3287, 3288, 7, 14, 0, 0, 3288, 3289, 7, 10, 0, 0, 3289, 3290, 7, 18, 0, 0, 3290, 622, 1, 0, 0, 0, 3291, 3292, 7, 18, 0, 0, 3292, 3293, 7, 4, 0, 0, 3293, 3294, 7, 2, 0, 0, 3294, 3295, 7, 12, 0, 0, 3295, 3296, 7, 8, 0, 0, 3296, 3297, 7, 21, 0, 0, 3297, 3298, 5, 95, 0, 0, 3298, 3299, 7, 14, 0, 0, 3299, 3300, 7, 2, 0, 0, 3300, 3301, 7, 15, 0, 0, 3301, 3302, 7, 20, 0, 0, 3302, 3303, 7, 16, 0, 0, 3303, 3304, 7, 6, 0, 0, 3304, 624, 1, 0, 0, 0, 3305, 3306, 7, 25, 0, 0, 3306, 3307, 7, 17, 0, 0, 3307, 3308, 7, 10, 0, 0, 3308, 3309, 7, 16, 0, 0, 3309, 3310, 7, 2, 0, 0, 3310, 3311, 5, 95, 0, 0, 3311, 3312, 7, 3, 0, 0, 3312, 3313, 7, 15, 0, 0, 3313, 3314, 7, 3, 0, 0, 3314, 3315, 7, 14, 0, 0, 3315, 3316, 7, 23, 0, 0, 3316, 3317, 7, 24, 0, 0, 3317, 3318, 7, 2, 0, 0, 3318, 3319, 7, 4, 0, 0, 3319, 626, 1, 0, 0, 0, 3320, 3321, 7, 25, 0, 0, 3321, 3322, 7, 17, 0, 0, 3322, 3323, 7, 10, 0, 0, 3323, 3324, 7, 16, 0, 0, 3324, 3325, 7, 2, 0, 0, 3325, 3326, 5, 95, 0, 0, 3326, 3327, 7, 12, 0, 0, 3327, 3328, 7, 8, 0, 0, 3328, 3329, 7, 2, 0, 0, 3329, 3330, 7, 14, 0, 0, 3330, 3331, 7, 7, 0, 0, 3331, 3332, 5, 95, 0, 0, 3332, 3333, 7, 1, 0, 0, 3333, 3334, 7, 17, 0, 0, 3334, 3335, 7, 12, 0, 0, 3335, 3336, 7, 12, 0, 0, 3336, 3337, 7, 8, 0, 0, 3337, 3338, 7, 21, 0, 0, 3338, 628, 1, 0, 0, 0, 3339, 3340, 7, 4, 0, 0, 3340, 3341, 7, 2, 0, 0, 3341, 3342, 7, 11, 0, 0, 3342, 3343, 7, 4, 0, 0, 3343, 3344, 7, 8, 0, 0, 3344, 3345, 7, 16, 0, 0, 3345, 3346, 7, 2, 0, 0, 3346, 630, 1, 0, 0, 0, 3347, 3348, 7, 1, 0, 0, 3348, 3349, 7, 14, 0, 0, 3349, 3350, 7, 10, 0, 0, 3350, 3351, 7, 18, 0, 0, 3351, 632, 1, 0, 0, 0, 3352, 3353, 7, 16, 0, 0, 3353, 3354, 7, 8, 0, 0, 3354, 3355, 7, 2, 0, 0, 3355, 3356, 5, 95, 0, 0, 3356, 3357, 7, 9, 0, 0, 3357, 3358, 7, 4, 0, 0, 3358, 3359, 7, 2, 0, 0, 3359, 3360, 7, 3, 0, 0, 3360, 3361, 7, 22, 0, 0, 3361, 3362, 7, 2, 0, 0, 3362, 3363, 7, 4, 0, 0, 3363, 634, 1, 0, 0, 0, 3364, 3365, 7, 16, 0, 0, 3365, 3366, 7, 23, 0, 0, 3366, 3367, 7, 18, 0, 0, 3367, 3368, 7, 2, 0, 0, 3368, 636, 1, 0, 0, 0, 3369, 3370, 7, 24, 0, 0, 3370, 3371, 7, 2, 0, 0, 3371, 3372, 7, 4, 0, 0, 3372, 3373, 7, 10, 0, 0, 3373, 3374, 5, 95, 0, 0, 3374, 3375, 7, 16, 0, 0, 3375, 3376, 7, 2, 0, 0, 3376, 3377, 7, 4, 0, 0, 3377, 3378, 7, 13, 0, 0, 3378, 3379, 7, 1, 0, 0, 3379, 3380, 5, 95, 0, 0, 3380, 3381, 7, 25, 0, 0, 3381, 3382, 7, 17, 0, 0, 3382, 3383, 7, 2, 0, 0, 3383, 3384, 7, 4, 0, 0, 3384, 3385, 7, 23, 0, 0, 3385, 638, 1, 0, 0, 0, 3386, 3387, 7, 1, 0, 0, 3387, 3388, 7, 18, 0, 0, 3388, 3389, 7, 3, 0, 0, 3389, 3390, 7, 15, 0, 0, 3390, 640, 1, 0, 0, 0, 3391, 3392, 7, 13, 0, 0, 3392, 3393, 7, 1, 0, 0, 3393, 642, 1, 0, 0, 0, 3394, 3395, 7, 1, 0, 0, 3395, 644, 1, 0, 0, 0, 3396, 3397, 7, 13, 0, 0, 3397, 646, 1, 0, 0, 0, 3398, 3399, 7, 6, 0, 0, 3399, 648, 1, 0, 0, 0, 3400, 3401, 7, 11, 0, 0, 3401, 650, 1, 0, 0, 0, 3402, 3403, 7, 25, 0, 0, 3403, 652, 1, 0, 0, 0, 3404, 3405, 7, 23, 0, 0, 3405, 654, 1, 0, 0, 0, 3406, 3407, 3, 665, 332, 0, 3407, 656, 1, 0, 0, 0, 3408, 3409, 3, 667, 333, 0, 3409, 658, 1, 0, 0, 0, 3410, 3412, 3, 677, 338, 0, 3411, 3410, 1, 0, 0, 0, 3412, 3413, 1, 0, 0, 0, 3413, 3411, 1, 0, 0, 0, 3413, 3414, 1, 0, 0, 0, 3414, 660, 1, 0, 0, 0, 3415, 3417, 3, 677, 338, 0, 3416, 3415, 1, 0, 0, 0, 3417, 3418, 1, 0, 0, 0, 3418, 3416, 1, 0, 0, 0, 3418, 3419, 1, 0, 0, 0, 3419, 3421, 1, 0, 0, 0, 3420, 3416, 1, 0, 0, 0, 3420, 3421, 1, 0, 0, 0, 3421, 3422, 1, 0, 0, 0, 3422, 3424, 5, 46, 0, 0, 3423, 3425, 3, 677, 338, 0, 3424, 3423, 1, 0, 0, 0, 3425, 3426, 1, 0, 0, 0, 3426, 3424, 1, 0, 0, 0, 3426, 3427, 1, 0, 0, 0, 3427, 662, 1, 0, 0, 0, 3428, 3430, 7, 26, 0, 0, 3429, 3431, 7, 27, 0, 0, 3430, 3429, 1, 0, 0, 0, 3431, 3432, 1, 0, 0, 0, 3432, 3430, 1, 0, 0, 0, 3432, 3433, 1, 0, 0, 0, 3433, 3435, 1, 0, 0, 0, 3434, 3428, 1, 0, 0, 0, 3435, 3436, 1, 0, 0, 0, 3436, 3434, 1, 0, 0, 0, 3436, 3437, 1, 0, 0, 0, 3437, 664, 1, 0, 0, 0, 3438, 3442, 7, 28, 0, 0, 3439, 3441, 7, 29, 0, 0, 3440, 3439, 1, 0, 0, 0, 3441, 3444, 1, 0, 0, 0, 3442, 3440, 1, 0, 0, 0, 3442, 3443, 1, 0, 0, 0, 3443, 666, 1, 0, 0, 0, 3444, 3442, 1, 0, 0, 0, 3445, 3447, 7, 30, 0, 0, 3446, 3445, 1, 0, 0, 0, 3447, 3448, 1, 0, 0, 0, 3448, 3449, 1, 0, 0, 0, 3448, 3446, 1, 0, 0, 0, 3449, 3453, 1, 0, 0, 0, 3450, 3452, 7, 29, 0, 0, 3451, 3450, 1, 0, 0, 0, 3452, 3455, 1, 0, 0, 0, 3453, 3451, 1, 0, 0, 0, 3453, 3454, 1, 0, 0, 0, 3454, 3456, 1, 0, 0, 0, 3455, 3453, 1, 0, 0, 0, 3456, 3457, 3, 247, 123, 0, 3457, 668, 1, 0, 0, 0, 3458, 3460, 3, 667, 333, 0, 3459, 3458, 1, 0, 0, 0, 3459, 3460, 1, 0, 0, 0, 3460, 3461, 1, 0, 0, 0, 3461, 3462, 3, 665, 332, 0, 3462, 3463, 3, 663, 331, 0, 3463, 670, 1, 0, 0, 0, 3464, 3472, 5, 34, 0, 0, 3465, 3466, 5, 92, 0, 0, 3466, 3471, 9, 0, 0, 0, 3467, 3468, 5, 34, 0, 0, 3468, 3471, 5, 34, 0, 0, 3469, 3471, 8, 31, 0, 0, 3470, 3465, 1, 0, 0, 0, 3470, 3467, 1, 0, 0, 0, 3470, 3469, 1, 0, 0, 0, 3471, 3474, 1, 0, 0, 0, 3472, 3470, 1, 0, 0, 0, 3472, 3473, 1, 0, 0, 0, 3473, 3475, 1, 0, 0, 0, 3474, 3472, 1, 0, 0, 0, 3475, 3476, 5, 34, 0, 0, 3476, 672, 1, 0, 0, 0, 3477, 3485, 5, 39, 0, 0, 3478, 3479, 5, 92, 0, 0, 3479, 3484, 9, 0, 0, 0, 3480, 3481, 5, 39, 0, 0, 3481, 3484, 5, 39, 0, 0, 3482, 3484, 8, 32, 0, 0, 3483, 3478, 1, 0, 0, 0, 3483, 3480, 1, 0, 0, 0, 3483, 3482, 1, 0, 0, 0, 3484, 3487, 1, 0, 0, 0, 3485, 3483, 1, 0, 0, 0, 3485, 3486, 1, 0, 0, 0, 3486, 3488, 1, 0, 0, 0, 3487, 3485, 1, 0, 0, 0, 3488, 3489, 5, 39, 0, 0, 3489, 674, 1, 0, 0, 0, 3490, 3498, 5, 96, 0, 0, 3491, 3492, 5, 92, 0, 0, 3492, 3497, 9, 0, 0, 0, 3493, 3494, 5, 96, 0, 0, 3494, 3497, 5, 96, 0, 0, 3495, 3497, 8, 33, 0, 0, 3496, 3491, 1, 0, 0, 0, 3496, 3493, 1, 0, 0, 0, 3496, 3495, 1, 0, 0, 0, 3497, 3500, 1, 0, 0, 0, 3498, 3496, 1, 0, 0, 0, 3498, 3499, 1, 0, 0, 0, 3499, 3501, 1, 0, 0, 0, 3500, 3498, 1, 0, 0, 0, 3501, 3502, 5, 96, 0, 0, 3502, 676, 1, 0, 0, 0, 3503, 3504, 7, 34, 0, 0, 3504, 678, 1, 0, 0, 0, 3505, 3506, 9, 0, 0, 0, 3506, 3507, 1, 0, 0, 0, 3507, 3508, 6, 339, 1, 0, 3508, 680, 1, 0, 0, 0, 18, 0, 684, 3413, 3418, 3420, 3426, 3432, 3436, 3442, 3448, 3453, 3459, 3470, 3472, 3483, 3485, 3496, 3498, 2, 0, 1, 0, 0, 3, 0] \ No newline at end of file diff --git a/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.tokens b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.tokens new file mode 100644 index 000000000000..4779948fd379 --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.tokens @@ -0,0 +1,659 @@ +SPACE=1 +SEARCH=2 +DESCRIBE=3 +SHOW=4 +FROM=5 +WHERE=6 +FIELDS=7 +RENAME=8 +STATS=9 +DEDUP=10 +SORT=11 +EVAL=12 +HEAD=13 +TOP=14 +RARE=15 +PARSE=16 +METHOD=17 +REGEX=18 +PUNCT=19 +GROK=20 +PATTERN=21 +PATTERNS=22 +NEW_FIELD=23 +KMEANS=24 +AD=25 +ML=26 +AS=27 +BY=28 +SOURCE=29 +INDEX=30 +D=31 +DESC=32 +DATASOURCES=33 +SORTBY=34 +AUTO=35 +STR=36 +IP=37 +NUM=38 +KEEPEMPTY=39 +CONSECUTIVE=40 +DEDUP_SPLITVALUES=41 +PARTITIONS=42 +ALLNUM=43 +DELIM=44 +CENTROIDS=45 +ITERATIONS=46 +DISTANCE_TYPE=47 +NUMBER_OF_TREES=48 +SHINGLE_SIZE=49 +SAMPLE_SIZE=50 +OUTPUT_AFTER=51 +TIME_DECAY=52 +ANOMALY_RATE=53 +CATEGORY_FIELD=54 +TIME_FIELD=55 +TIME_ZONE=56 +TRAINING_DATA_SIZE=57 +ANOMALY_SCORE_THRESHOLD=58 +CASE=59 +IN=60 +NOT=61 +OR=62 +AND=63 +XOR=64 +TRUE=65 +FALSE=66 +REGEXP=67 +CONVERT_TZ=68 +DATETIME=69 +DAY=70 +DAY_HOUR=71 +DAY_MICROSECOND=72 +DAY_MINUTE=73 +DAY_OF_YEAR=74 +DAY_SECOND=75 +HOUR=76 +HOUR_MICROSECOND=77 +HOUR_MINUTE=78 +HOUR_OF_DAY=79 +HOUR_SECOND=80 +INTERVAL=81 +MICROSECOND=82 +MILLISECOND=83 +MINUTE=84 +MINUTE_MICROSECOND=85 +MINUTE_OF_DAY=86 +MINUTE_OF_HOUR=87 +MINUTE_SECOND=88 +MONTH=89 +MONTH_OF_YEAR=90 +QUARTER=91 +SECOND=92 +SECOND_MICROSECOND=93 +SECOND_OF_MINUTE=94 +WEEK=95 +WEEK_OF_YEAR=96 +YEAR=97 +YEAR_MONTH=98 +DATAMODEL=99 +LOOKUP=100 +SAVEDSEARCH=101 +INT=102 +INTEGER=103 +DOUBLE=104 +LONG=105 +FLOAT=106 +STRING=107 +BOOLEAN=108 +PIPE=109 +COMMA=110 +DOT=111 +EQUAL=112 +GREATER=113 +LESS=114 +NOT_GREATER=115 +NOT_LESS=116 +NOT_EQUAL=117 +PLUS=118 +MINUS=119 +STAR=120 +DIVIDE=121 +MODULE=122 +EXCLAMATION_SYMBOL=123 +COLON=124 +LT_PRTHS=125 +RT_PRTHS=126 +LT_SQR_PRTHS=127 +RT_SQR_PRTHS=128 +SINGLE_QUOTE=129 +DOUBLE_QUOTE=130 +BACKTICK=131 +BIT_NOT_OP=132 +BIT_AND_OP=133 +BIT_XOR_OP=134 +AVG=135 +COUNT=136 +DISTINCT_COUNT=137 +ESTDC=138 +ESTDC_ERROR=139 +MAX=140 +MEAN=141 +MEDIAN=142 +MIN=143 +MODE=144 +RANGE=145 +STDEV=146 +STDEVP=147 +SUM=148 +SUMSQ=149 +VAR_SAMP=150 +VAR_POP=151 +STDDEV_SAMP=152 +STDDEV_POP=153 +PERCENTILE=154 +TAKE=155 +FIRST=156 +LAST=157 +LIST=158 +VALUES=159 +EARLIEST=160 +EARLIEST_TIME=161 +LATEST=162 +LATEST_TIME=163 +PER_DAY=164 +PER_HOUR=165 +PER_MINUTE=166 +PER_SECOND=167 +RATE=168 +SPARKLINE=169 +C=170 +DC=171 +ABS=172 +CBRT=173 +CEIL=174 +CEILING=175 +CONV=176 +CRC32=177 +E=178 +EXP=179 +FLOOR=180 +LN=181 +LOG=182 +LOG10=183 +LOG2=184 +MOD=185 +PI=186 +POSITION=187 +POW=188 +POWER=189 +RAND=190 +ROUND=191 +SIGN=192 +SQRT=193 +TRUNCATE=194 +ACOS=195 +ASIN=196 +ATAN=197 +ATAN2=198 +COS=199 +COT=200 +DEGREES=201 +RADIANS=202 +SIN=203 +TAN=204 +ADDDATE=205 +ADDTIME=206 +CURDATE=207 +CURRENT_DATE=208 +CURRENT_TIME=209 +CURRENT_TIMESTAMP=210 +CURTIME=211 +DATE=212 +DATEDIFF=213 +DATE_ADD=214 +DATE_FORMAT=215 +DATE_SUB=216 +DAYNAME=217 +DAYOFMONTH=218 +DAYOFWEEK=219 +DAYOFYEAR=220 +DAY_OF_MONTH=221 +DAY_OF_WEEK=222 +EXTRACT=223 +FROM_DAYS=224 +FROM_UNIXTIME=225 +GET_FORMAT=226 +LAST_DAY=227 +LOCALTIME=228 +LOCALTIMESTAMP=229 +MAKEDATE=230 +MAKETIME=231 +MONTHNAME=232 +NOW=233 +PERIOD_ADD=234 +PERIOD_DIFF=235 +SEC_TO_TIME=236 +STR_TO_DATE=237 +SUBDATE=238 +SUBTIME=239 +SYSDATE=240 +TIME=241 +TIMEDIFF=242 +TIMESTAMP=243 +TIMESTAMPADD=244 +TIMESTAMPDIFF=245 +TIME_FORMAT=246 +TIME_TO_SEC=247 +TO_DAYS=248 +TO_SECONDS=249 +UNIX_TIMESTAMP=250 +UTC_DATE=251 +UTC_TIME=252 +UTC_TIMESTAMP=253 +WEEKDAY=254 +YEARWEEK=255 +SUBSTR=256 +SUBSTRING=257 +LTRIM=258 +RTRIM=259 +TRIM=260 +TO=261 +LOWER=262 +UPPER=263 +CONCAT=264 +CONCAT_WS=265 +LENGTH=266 +STRCMP=267 +RIGHT=268 +LEFT=269 +ASCII=270 +LOCATE=271 +REPLACE=272 +REVERSE=273 +CAST=274 +LIKE=275 +ISNULL=276 +ISNOTNULL=277 +IFNULL=278 +NULLIF=279 +IF=280 +TYPEOF=281 +MATCH=282 +MATCH_PHRASE=283 +MATCH_PHRASE_PREFIX=284 +MATCH_BOOL_PREFIX=285 +SIMPLE_QUERY_STRING=286 +MULTI_MATCH=287 +QUERY_STRING=288 +ALLOW_LEADING_WILDCARD=289 +ANALYZE_WILDCARD=290 +ANALYZER=291 +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY=292 +BOOST=293 +CUTOFF_FREQUENCY=294 +DEFAULT_FIELD=295 +DEFAULT_OPERATOR=296 +ENABLE_POSITION_INCREMENTS=297 +ESCAPE=298 +FLAGS=299 +FUZZY_MAX_EXPANSIONS=300 +FUZZY_PREFIX_LENGTH=301 +FUZZY_TRANSPOSITIONS=302 +FUZZY_REWRITE=303 +FUZZINESS=304 +LENIENT=305 +LOW_FREQ_OPERATOR=306 +MAX_DETERMINIZED_STATES=307 +MAX_EXPANSIONS=308 +MINIMUM_SHOULD_MATCH=309 +OPERATOR=310 +PHRASE_SLOP=311 +PREFIX_LENGTH=312 +QUOTE_ANALYZER=313 +QUOTE_FIELD_SUFFIX=314 +REWRITE=315 +SLOP=316 +TIE_BREAKER=317 +TYPE=318 +ZERO_TERMS_QUERY=319 +SPAN=320 +MS=321 +S=322 +M=323 +H=324 +W=325 +Q=326 +Y=327 +ID=328 +CLUSTER=329 +INTEGER_LITERAL=330 +DECIMAL_LITERAL=331 +ID_DATE_SUFFIX=332 +DQUOTA_STRING=333 +SQUOTA_STRING=334 +BQUOTA_STRING=335 +ERROR_RECOGNITION=336 +'SEARCH'=2 +'DESCRIBE'=3 +'SHOW'=4 +'FROM'=5 +'WHERE'=6 +'FIELDS'=7 +'RENAME'=8 +'STATS'=9 +'DEDUP'=10 +'SORT'=11 +'EVAL'=12 +'HEAD'=13 +'TOP'=14 +'RARE'=15 +'PARSE'=16 +'METHOD'=17 +'REGEX'=18 +'PUNCT'=19 +'GROK'=20 +'PATTERN'=21 +'PATTERNS'=22 +'NEW_FIELD'=23 +'KMEANS'=24 +'AD'=25 +'ML'=26 +'AS'=27 +'BY'=28 +'SOURCE'=29 +'INDEX'=30 +'D'=31 +'DESC'=32 +'DATASOURCES'=33 +'SORTBY'=34 +'AUTO'=35 +'STR'=36 +'IP'=37 +'NUM'=38 +'KEEPEMPTY'=39 +'CONSECUTIVE'=40 +'DEDUP_SPLITVALUES'=41 +'PARTITIONS'=42 +'ALLNUM'=43 +'DELIM'=44 +'CENTROIDS'=45 +'ITERATIONS'=46 +'DISTANCE_TYPE'=47 +'NUMBER_OF_TREES'=48 +'SHINGLE_SIZE'=49 +'SAMPLE_SIZE'=50 +'OUTPUT_AFTER'=51 +'TIME_DECAY'=52 +'ANOMALY_RATE'=53 +'CATEGORY_FIELD'=54 +'TIME_FIELD'=55 +'TIME_ZONE'=56 +'TRAINING_DATA_SIZE'=57 +'ANOMALY_SCORE_THRESHOLD'=58 +'CASE'=59 +'IN'=60 +'NOT'=61 +'OR'=62 +'AND'=63 +'XOR'=64 +'TRUE'=65 +'FALSE'=66 +'REGEXP'=67 +'CONVERT_TZ'=68 +'DATETIME'=69 +'DAY'=70 +'DAY_HOUR'=71 +'DAY_MICROSECOND'=72 +'DAY_MINUTE'=73 +'DAY_OF_YEAR'=74 +'DAY_SECOND'=75 +'HOUR'=76 +'HOUR_MICROSECOND'=77 +'HOUR_MINUTE'=78 +'HOUR_OF_DAY'=79 +'HOUR_SECOND'=80 +'INTERVAL'=81 +'MICROSECOND'=82 +'MILLISECOND'=83 +'MINUTE'=84 +'MINUTE_MICROSECOND'=85 +'MINUTE_OF_DAY'=86 +'MINUTE_OF_HOUR'=87 +'MINUTE_SECOND'=88 +'MONTH'=89 +'MONTH_OF_YEAR'=90 +'QUARTER'=91 +'SECOND'=92 +'SECOND_MICROSECOND'=93 +'SECOND_OF_MINUTE'=94 +'WEEK'=95 +'WEEK_OF_YEAR'=96 +'YEAR'=97 +'YEAR_MONTH'=98 +'DATAMODEL'=99 +'LOOKUP'=100 +'SAVEDSEARCH'=101 +'INT'=102 +'INTEGER'=103 +'DOUBLE'=104 +'LONG'=105 +'FLOAT'=106 +'STRING'=107 +'BOOLEAN'=108 +'|'=109 +','=110 +'.'=111 +'='=112 +'>'=113 +'<'=114 +'+'=118 +'-'=119 +'*'=120 +'/'=121 +'%'=122 +'!'=123 +':'=124 +'('=125 +')'=126 +'['=127 +']'=128 +'\''=129 +'"'=130 +'`'=131 +'~'=132 +'&'=133 +'^'=134 +'AVG'=135 +'COUNT'=136 +'DISTINCT_COUNT'=137 +'ESTDC'=138 +'ESTDC_ERROR'=139 +'MAX'=140 +'MEAN'=141 +'MEDIAN'=142 +'MIN'=143 +'MODE'=144 +'RANGE'=145 +'STDEV'=146 +'STDEVP'=147 +'SUM'=148 +'SUMSQ'=149 +'VAR_SAMP'=150 +'VAR_POP'=151 +'STDDEV_SAMP'=152 +'STDDEV_POP'=153 +'PERCENTILE'=154 +'TAKE'=155 +'FIRST'=156 +'LAST'=157 +'LIST'=158 +'VALUES'=159 +'EARLIEST'=160 +'EARLIEST_TIME'=161 +'LATEST'=162 +'LATEST_TIME'=163 +'PER_DAY'=164 +'PER_HOUR'=165 +'PER_MINUTE'=166 +'PER_SECOND'=167 +'RATE'=168 +'SPARKLINE'=169 +'C'=170 +'DC'=171 +'ABS'=172 +'CBRT'=173 +'CEIL'=174 +'CEILING'=175 +'CONV'=176 +'CRC32'=177 +'E'=178 +'EXP'=179 +'FLOOR'=180 +'LN'=181 +'LOG'=182 +'LOG10'=183 +'LOG2'=184 +'MOD'=185 +'PI'=186 +'POSITION'=187 +'POW'=188 +'POWER'=189 +'RAND'=190 +'ROUND'=191 +'SIGN'=192 +'SQRT'=193 +'TRUNCATE'=194 +'ACOS'=195 +'ASIN'=196 +'ATAN'=197 +'ATAN2'=198 +'COS'=199 +'COT'=200 +'DEGREES'=201 +'RADIANS'=202 +'SIN'=203 +'TAN'=204 +'ADDDATE'=205 +'ADDTIME'=206 +'CURDATE'=207 +'CURRENT_DATE'=208 +'CURRENT_TIME'=209 +'CURRENT_TIMESTAMP'=210 +'CURTIME'=211 +'DATE'=212 +'DATEDIFF'=213 +'DATE_ADD'=214 +'DATE_FORMAT'=215 +'DATE_SUB'=216 +'DAYNAME'=217 +'DAYOFMONTH'=218 +'DAYOFWEEK'=219 +'DAYOFYEAR'=220 +'DAY_OF_MONTH'=221 +'DAY_OF_WEEK'=222 +'EXTRACT'=223 +'FROM_DAYS'=224 +'FROM_UNIXTIME'=225 +'GET_FORMAT'=226 +'LAST_DAY'=227 +'LOCALTIME'=228 +'LOCALTIMESTAMP'=229 +'MAKEDATE'=230 +'MAKETIME'=231 +'MONTHNAME'=232 +'NOW'=233 +'PERIOD_ADD'=234 +'PERIOD_DIFF'=235 +'SEC_TO_TIME'=236 +'STR_TO_DATE'=237 +'SUBDATE'=238 +'SUBTIME'=239 +'SYSDATE'=240 +'TIME'=241 +'TIMEDIFF'=242 +'TIMESTAMP'=243 +'TIMESTAMPADD'=244 +'TIMESTAMPDIFF'=245 +'TIME_FORMAT'=246 +'TIME_TO_SEC'=247 +'TO_DAYS'=248 +'TO_SECONDS'=249 +'UNIX_TIMESTAMP'=250 +'UTC_DATE'=251 +'UTC_TIME'=252 +'UTC_TIMESTAMP'=253 +'WEEKDAY'=254 +'YEARWEEK'=255 +'SUBSTR'=256 +'SUBSTRING'=257 +'LTRIM'=258 +'RTRIM'=259 +'TRIM'=260 +'TO'=261 +'LOWER'=262 +'UPPER'=263 +'CONCAT'=264 +'CONCAT_WS'=265 +'LENGTH'=266 +'STRCMP'=267 +'RIGHT'=268 +'LEFT'=269 +'ASCII'=270 +'LOCATE'=271 +'REPLACE'=272 +'REVERSE'=273 +'CAST'=274 +'LIKE'=275 +'ISNULL'=276 +'ISNOTNULL'=277 +'IFNULL'=278 +'NULLIF'=279 +'IF'=280 +'TYPEOF'=281 +'MATCH'=282 +'MATCH_PHRASE'=283 +'MATCH_PHRASE_PREFIX'=284 +'MATCH_BOOL_PREFIX'=285 +'SIMPLE_QUERY_STRING'=286 +'MULTI_MATCH'=287 +'QUERY_STRING'=288 +'ALLOW_LEADING_WILDCARD'=289 +'ANALYZE_WILDCARD'=290 +'ANALYZER'=291 +'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY'=292 +'BOOST'=293 +'CUTOFF_FREQUENCY'=294 +'DEFAULT_FIELD'=295 +'DEFAULT_OPERATOR'=296 +'ENABLE_POSITION_INCREMENTS'=297 +'ESCAPE'=298 +'FLAGS'=299 +'FUZZY_MAX_EXPANSIONS'=300 +'FUZZY_PREFIX_LENGTH'=301 +'FUZZY_TRANSPOSITIONS'=302 +'FUZZY_REWRITE'=303 +'FUZZINESS'=304 +'LENIENT'=305 +'LOW_FREQ_OPERATOR'=306 +'MAX_DETERMINIZED_STATES'=307 +'MAX_EXPANSIONS'=308 +'MINIMUM_SHOULD_MATCH'=309 +'OPERATOR'=310 +'PHRASE_SLOP'=311 +'PREFIX_LENGTH'=312 +'QUOTE_ANALYZER'=313 +'QUOTE_FIELD_SUFFIX'=314 +'REWRITE'=315 +'SLOP'=316 +'TIE_BREAKER'=317 +'TYPE'=318 +'ZERO_TERMS_QUERY'=319 +'SPAN'=320 +'MS'=321 +'S'=322 +'M'=323 +'H'=324 +'W'=325 +'Q'=326 +'Y'=327 diff --git a/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.ts b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.ts new file mode 100644 index 000000000000..d9fb44016e20 --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLLexer.ts @@ -0,0 +1,1880 @@ +// Generated from ./src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLLexer.g4 by ANTLR 4.13.1 + +import * as antlr from "antlr4ng"; +import { Token } from "antlr4ng"; + + +export class OpenSearchPPLLexer extends antlr.Lexer { + public static readonly SPACE = 1; + public static readonly SEARCH = 2; + public static readonly DESCRIBE = 3; + public static readonly SHOW = 4; + public static readonly FROM = 5; + public static readonly WHERE = 6; + public static readonly FIELDS = 7; + public static readonly RENAME = 8; + public static readonly STATS = 9; + public static readonly DEDUP = 10; + public static readonly SORT = 11; + public static readonly EVAL = 12; + public static readonly HEAD = 13; + public static readonly TOP = 14; + public static readonly RARE = 15; + public static readonly PARSE = 16; + public static readonly METHOD = 17; + public static readonly REGEX = 18; + public static readonly PUNCT = 19; + public static readonly GROK = 20; + public static readonly PATTERN = 21; + public static readonly PATTERNS = 22; + public static readonly NEW_FIELD = 23; + public static readonly KMEANS = 24; + public static readonly AD = 25; + public static readonly ML = 26; + public static readonly AS = 27; + public static readonly BY = 28; + public static readonly SOURCE = 29; + public static readonly INDEX = 30; + public static readonly D = 31; + public static readonly DESC = 32; + public static readonly DATASOURCES = 33; + public static readonly SORTBY = 34; + public static readonly AUTO = 35; + public static readonly STR = 36; + public static readonly IP = 37; + public static readonly NUM = 38; + public static readonly KEEPEMPTY = 39; + public static readonly CONSECUTIVE = 40; + public static readonly DEDUP_SPLITVALUES = 41; + public static readonly PARTITIONS = 42; + public static readonly ALLNUM = 43; + public static readonly DELIM = 44; + public static readonly CENTROIDS = 45; + public static readonly ITERATIONS = 46; + public static readonly DISTANCE_TYPE = 47; + public static readonly NUMBER_OF_TREES = 48; + public static readonly SHINGLE_SIZE = 49; + public static readonly SAMPLE_SIZE = 50; + public static readonly OUTPUT_AFTER = 51; + public static readonly TIME_DECAY = 52; + public static readonly ANOMALY_RATE = 53; + public static readonly CATEGORY_FIELD = 54; + public static readonly TIME_FIELD = 55; + public static readonly TIME_ZONE = 56; + public static readonly TRAINING_DATA_SIZE = 57; + public static readonly ANOMALY_SCORE_THRESHOLD = 58; + public static readonly CASE = 59; + public static readonly IN = 60; + public static readonly NOT = 61; + public static readonly OR = 62; + public static readonly AND = 63; + public static readonly XOR = 64; + public static readonly TRUE = 65; + public static readonly FALSE = 66; + public static readonly REGEXP = 67; + public static readonly CONVERT_TZ = 68; + public static readonly DATETIME = 69; + public static readonly DAY = 70; + public static readonly DAY_HOUR = 71; + public static readonly DAY_MICROSECOND = 72; + public static readonly DAY_MINUTE = 73; + public static readonly DAY_OF_YEAR = 74; + public static readonly DAY_SECOND = 75; + public static readonly HOUR = 76; + public static readonly HOUR_MICROSECOND = 77; + public static readonly HOUR_MINUTE = 78; + public static readonly HOUR_OF_DAY = 79; + public static readonly HOUR_SECOND = 80; + public static readonly INTERVAL = 81; + public static readonly MICROSECOND = 82; + public static readonly MILLISECOND = 83; + public static readonly MINUTE = 84; + public static readonly MINUTE_MICROSECOND = 85; + public static readonly MINUTE_OF_DAY = 86; + public static readonly MINUTE_OF_HOUR = 87; + public static readonly MINUTE_SECOND = 88; + public static readonly MONTH = 89; + public static readonly MONTH_OF_YEAR = 90; + public static readonly QUARTER = 91; + public static readonly SECOND = 92; + public static readonly SECOND_MICROSECOND = 93; + public static readonly SECOND_OF_MINUTE = 94; + public static readonly WEEK = 95; + public static readonly WEEK_OF_YEAR = 96; + public static readonly YEAR = 97; + public static readonly YEAR_MONTH = 98; + public static readonly DATAMODEL = 99; + public static readonly LOOKUP = 100; + public static readonly SAVEDSEARCH = 101; + public static readonly INT = 102; + public static readonly INTEGER = 103; + public static readonly DOUBLE = 104; + public static readonly LONG = 105; + public static readonly FLOAT = 106; + public static readonly STRING = 107; + public static readonly BOOLEAN = 108; + public static readonly PIPE = 109; + public static readonly COMMA = 110; + public static readonly DOT = 111; + public static readonly EQUAL = 112; + public static readonly GREATER = 113; + public static readonly LESS = 114; + public static readonly NOT_GREATER = 115; + public static readonly NOT_LESS = 116; + public static readonly NOT_EQUAL = 117; + public static readonly PLUS = 118; + public static readonly MINUS = 119; + public static readonly STAR = 120; + public static readonly DIVIDE = 121; + public static readonly MODULE = 122; + public static readonly EXCLAMATION_SYMBOL = 123; + public static readonly COLON = 124; + public static readonly LT_PRTHS = 125; + public static readonly RT_PRTHS = 126; + public static readonly LT_SQR_PRTHS = 127; + public static readonly RT_SQR_PRTHS = 128; + public static readonly SINGLE_QUOTE = 129; + public static readonly DOUBLE_QUOTE = 130; + public static readonly BACKTICK = 131; + public static readonly BIT_NOT_OP = 132; + public static readonly BIT_AND_OP = 133; + public static readonly BIT_XOR_OP = 134; + public static readonly AVG = 135; + public static readonly COUNT = 136; + public static readonly DISTINCT_COUNT = 137; + public static readonly ESTDC = 138; + public static readonly ESTDC_ERROR = 139; + public static readonly MAX = 140; + public static readonly MEAN = 141; + public static readonly MEDIAN = 142; + public static readonly MIN = 143; + public static readonly MODE = 144; + public static readonly RANGE = 145; + public static readonly STDEV = 146; + public static readonly STDEVP = 147; + public static readonly SUM = 148; + public static readonly SUMSQ = 149; + public static readonly VAR_SAMP = 150; + public static readonly VAR_POP = 151; + public static readonly STDDEV_SAMP = 152; + public static readonly STDDEV_POP = 153; + public static readonly PERCENTILE = 154; + public static readonly TAKE = 155; + public static readonly FIRST = 156; + public static readonly LAST = 157; + public static readonly LIST = 158; + public static readonly VALUES = 159; + public static readonly EARLIEST = 160; + public static readonly EARLIEST_TIME = 161; + public static readonly LATEST = 162; + public static readonly LATEST_TIME = 163; + public static readonly PER_DAY = 164; + public static readonly PER_HOUR = 165; + public static readonly PER_MINUTE = 166; + public static readonly PER_SECOND = 167; + public static readonly RATE = 168; + public static readonly SPARKLINE = 169; + public static readonly C = 170; + public static readonly DC = 171; + public static readonly ABS = 172; + public static readonly CBRT = 173; + public static readonly CEIL = 174; + public static readonly CEILING = 175; + public static readonly CONV = 176; + public static readonly CRC32 = 177; + public static readonly E = 178; + public static readonly EXP = 179; + public static readonly FLOOR = 180; + public static readonly LN = 181; + public static readonly LOG = 182; + public static readonly LOG10 = 183; + public static readonly LOG2 = 184; + public static readonly MOD = 185; + public static readonly PI = 186; + public static readonly POSITION = 187; + public static readonly POW = 188; + public static readonly POWER = 189; + public static readonly RAND = 190; + public static readonly ROUND = 191; + public static readonly SIGN = 192; + public static readonly SQRT = 193; + public static readonly TRUNCATE = 194; + public static readonly ACOS = 195; + public static readonly ASIN = 196; + public static readonly ATAN = 197; + public static readonly ATAN2 = 198; + public static readonly COS = 199; + public static readonly COT = 200; + public static readonly DEGREES = 201; + public static readonly RADIANS = 202; + public static readonly SIN = 203; + public static readonly TAN = 204; + public static readonly ADDDATE = 205; + public static readonly ADDTIME = 206; + public static readonly CURDATE = 207; + public static readonly CURRENT_DATE = 208; + public static readonly CURRENT_TIME = 209; + public static readonly CURRENT_TIMESTAMP = 210; + public static readonly CURTIME = 211; + public static readonly DATE = 212; + public static readonly DATEDIFF = 213; + public static readonly DATE_ADD = 214; + public static readonly DATE_FORMAT = 215; + public static readonly DATE_SUB = 216; + public static readonly DAYNAME = 217; + public static readonly DAYOFMONTH = 218; + public static readonly DAYOFWEEK = 219; + public static readonly DAYOFYEAR = 220; + public static readonly DAY_OF_MONTH = 221; + public static readonly DAY_OF_WEEK = 222; + public static readonly EXTRACT = 223; + public static readonly FROM_DAYS = 224; + public static readonly FROM_UNIXTIME = 225; + public static readonly GET_FORMAT = 226; + public static readonly LAST_DAY = 227; + public static readonly LOCALTIME = 228; + public static readonly LOCALTIMESTAMP = 229; + public static readonly MAKEDATE = 230; + public static readonly MAKETIME = 231; + public static readonly MONTHNAME = 232; + public static readonly NOW = 233; + public static readonly PERIOD_ADD = 234; + public static readonly PERIOD_DIFF = 235; + public static readonly SEC_TO_TIME = 236; + public static readonly STR_TO_DATE = 237; + public static readonly SUBDATE = 238; + public static readonly SUBTIME = 239; + public static readonly SYSDATE = 240; + public static readonly TIME = 241; + public static readonly TIMEDIFF = 242; + public static readonly TIMESTAMP = 243; + public static readonly TIMESTAMPADD = 244; + public static readonly TIMESTAMPDIFF = 245; + public static readonly TIME_FORMAT = 246; + public static readonly TIME_TO_SEC = 247; + public static readonly TO_DAYS = 248; + public static readonly TO_SECONDS = 249; + public static readonly UNIX_TIMESTAMP = 250; + public static readonly UTC_DATE = 251; + public static readonly UTC_TIME = 252; + public static readonly UTC_TIMESTAMP = 253; + public static readonly WEEKDAY = 254; + public static readonly YEARWEEK = 255; + public static readonly SUBSTR = 256; + public static readonly SUBSTRING = 257; + public static readonly LTRIM = 258; + public static readonly RTRIM = 259; + public static readonly TRIM = 260; + public static readonly TO = 261; + public static readonly LOWER = 262; + public static readonly UPPER = 263; + public static readonly CONCAT = 264; + public static readonly CONCAT_WS = 265; + public static readonly LENGTH = 266; + public static readonly STRCMP = 267; + public static readonly RIGHT = 268; + public static readonly LEFT = 269; + public static readonly ASCII = 270; + public static readonly LOCATE = 271; + public static readonly REPLACE = 272; + public static readonly REVERSE = 273; + public static readonly CAST = 274; + public static readonly LIKE = 275; + public static readonly ISNULL = 276; + public static readonly ISNOTNULL = 277; + public static readonly IFNULL = 278; + public static readonly NULLIF = 279; + public static readonly IF = 280; + public static readonly TYPEOF = 281; + public static readonly MATCH = 282; + public static readonly MATCH_PHRASE = 283; + public static readonly MATCH_PHRASE_PREFIX = 284; + public static readonly MATCH_BOOL_PREFIX = 285; + public static readonly SIMPLE_QUERY_STRING = 286; + public static readonly MULTI_MATCH = 287; + public static readonly QUERY_STRING = 288; + public static readonly ALLOW_LEADING_WILDCARD = 289; + public static readonly ANALYZE_WILDCARD = 290; + public static readonly ANALYZER = 291; + public static readonly AUTO_GENERATE_SYNONYMS_PHRASE_QUERY = 292; + public static readonly BOOST = 293; + public static readonly CUTOFF_FREQUENCY = 294; + public static readonly DEFAULT_FIELD = 295; + public static readonly DEFAULT_OPERATOR = 296; + public static readonly ENABLE_POSITION_INCREMENTS = 297; + public static readonly ESCAPE = 298; + public static readonly FLAGS = 299; + public static readonly FUZZY_MAX_EXPANSIONS = 300; + public static readonly FUZZY_PREFIX_LENGTH = 301; + public static readonly FUZZY_TRANSPOSITIONS = 302; + public static readonly FUZZY_REWRITE = 303; + public static readonly FUZZINESS = 304; + public static readonly LENIENT = 305; + public static readonly LOW_FREQ_OPERATOR = 306; + public static readonly MAX_DETERMINIZED_STATES = 307; + public static readonly MAX_EXPANSIONS = 308; + public static readonly MINIMUM_SHOULD_MATCH = 309; + public static readonly OPERATOR = 310; + public static readonly PHRASE_SLOP = 311; + public static readonly PREFIX_LENGTH = 312; + public static readonly QUOTE_ANALYZER = 313; + public static readonly QUOTE_FIELD_SUFFIX = 314; + public static readonly REWRITE = 315; + public static readonly SLOP = 316; + public static readonly TIE_BREAKER = 317; + public static readonly TYPE = 318; + public static readonly ZERO_TERMS_QUERY = 319; + public static readonly SPAN = 320; + public static readonly MS = 321; + public static readonly S = 322; + public static readonly M = 323; + public static readonly H = 324; + public static readonly W = 325; + public static readonly Q = 326; + public static readonly Y = 327; + public static readonly ID = 328; + public static readonly CLUSTER = 329; + public static readonly INTEGER_LITERAL = 330; + public static readonly DECIMAL_LITERAL = 331; + public static readonly ID_DATE_SUFFIX = 332; + public static readonly DQUOTA_STRING = 333; + public static readonly SQUOTA_STRING = 334; + public static readonly BQUOTA_STRING = 335; + public static readonly ERROR_RECOGNITION = 336; + + public static readonly channelNames = [ + "DEFAULT_TOKEN_CHANNEL", "HIDDEN", "WHITESPACE", "ERRORCHANNEL" + ]; + + public static readonly literalNames = [ + null, null, "'SEARCH'", "'DESCRIBE'", "'SHOW'", "'FROM'", "'WHERE'", + "'FIELDS'", "'RENAME'", "'STATS'", "'DEDUP'", "'SORT'", "'EVAL'", + "'HEAD'", "'TOP'", "'RARE'", "'PARSE'", "'METHOD'", "'REGEX'", "'PUNCT'", + "'GROK'", "'PATTERN'", "'PATTERNS'", "'NEW_FIELD'", "'KMEANS'", + "'AD'", "'ML'", "'AS'", "'BY'", "'SOURCE'", "'INDEX'", "'D'", "'DESC'", + "'DATASOURCES'", "'SORTBY'", "'AUTO'", "'STR'", "'IP'", "'NUM'", + "'KEEPEMPTY'", "'CONSECUTIVE'", "'DEDUP_SPLITVALUES'", "'PARTITIONS'", + "'ALLNUM'", "'DELIM'", "'CENTROIDS'", "'ITERATIONS'", "'DISTANCE_TYPE'", + "'NUMBER_OF_TREES'", "'SHINGLE_SIZE'", "'SAMPLE_SIZE'", "'OUTPUT_AFTER'", + "'TIME_DECAY'", "'ANOMALY_RATE'", "'CATEGORY_FIELD'", "'TIME_FIELD'", + "'TIME_ZONE'", "'TRAINING_DATA_SIZE'", "'ANOMALY_SCORE_THRESHOLD'", + "'CASE'", "'IN'", "'NOT'", "'OR'", "'AND'", "'XOR'", "'TRUE'", "'FALSE'", + "'REGEXP'", "'CONVERT_TZ'", "'DATETIME'", "'DAY'", "'DAY_HOUR'", + "'DAY_MICROSECOND'", "'DAY_MINUTE'", "'DAY_OF_YEAR'", "'DAY_SECOND'", + "'HOUR'", "'HOUR_MICROSECOND'", "'HOUR_MINUTE'", "'HOUR_OF_DAY'", + "'HOUR_SECOND'", "'INTERVAL'", "'MICROSECOND'", "'MILLISECOND'", + "'MINUTE'", "'MINUTE_MICROSECOND'", "'MINUTE_OF_DAY'", "'MINUTE_OF_HOUR'", + "'MINUTE_SECOND'", "'MONTH'", "'MONTH_OF_YEAR'", "'QUARTER'", "'SECOND'", + "'SECOND_MICROSECOND'", "'SECOND_OF_MINUTE'", "'WEEK'", "'WEEK_OF_YEAR'", + "'YEAR'", "'YEAR_MONTH'", "'DATAMODEL'", "'LOOKUP'", "'SAVEDSEARCH'", + "'INT'", "'INTEGER'", "'DOUBLE'", "'LONG'", "'FLOAT'", "'STRING'", + "'BOOLEAN'", "'|'", "','", "'.'", "'='", "'>'", "'<'", null, null, + null, "'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "':'", "'('", "')'", + "'['", "']'", "'''", "'\"'", "'`'", "'~'", "'&'", "'^'", "'AVG'", + "'COUNT'", "'DISTINCT_COUNT'", "'ESTDC'", "'ESTDC_ERROR'", "'MAX'", + "'MEAN'", "'MEDIAN'", "'MIN'", "'MODE'", "'RANGE'", "'STDEV'", "'STDEVP'", + "'SUM'", "'SUMSQ'", "'VAR_SAMP'", "'VAR_POP'", "'STDDEV_SAMP'", + "'STDDEV_POP'", "'PERCENTILE'", "'TAKE'", "'FIRST'", "'LAST'", "'LIST'", + "'VALUES'", "'EARLIEST'", "'EARLIEST_TIME'", "'LATEST'", "'LATEST_TIME'", + "'PER_DAY'", "'PER_HOUR'", "'PER_MINUTE'", "'PER_SECOND'", "'RATE'", + "'SPARKLINE'", "'C'", "'DC'", "'ABS'", "'CBRT'", "'CEIL'", "'CEILING'", + "'CONV'", "'CRC32'", "'E'", "'EXP'", "'FLOOR'", "'LN'", "'LOG'", + "'LOG10'", "'LOG2'", "'MOD'", "'PI'", "'POSITION'", "'POW'", "'POWER'", + "'RAND'", "'ROUND'", "'SIGN'", "'SQRT'", "'TRUNCATE'", "'ACOS'", + "'ASIN'", "'ATAN'", "'ATAN2'", "'COS'", "'COT'", "'DEGREES'", "'RADIANS'", + "'SIN'", "'TAN'", "'ADDDATE'", "'ADDTIME'", "'CURDATE'", "'CURRENT_DATE'", + "'CURRENT_TIME'", "'CURRENT_TIMESTAMP'", "'CURTIME'", "'DATE'", + "'DATEDIFF'", "'DATE_ADD'", "'DATE_FORMAT'", "'DATE_SUB'", "'DAYNAME'", + "'DAYOFMONTH'", "'DAYOFWEEK'", "'DAYOFYEAR'", "'DAY_OF_MONTH'", + "'DAY_OF_WEEK'", "'EXTRACT'", "'FROM_DAYS'", "'FROM_UNIXTIME'", + "'GET_FORMAT'", "'LAST_DAY'", "'LOCALTIME'", "'LOCALTIMESTAMP'", + "'MAKEDATE'", "'MAKETIME'", "'MONTHNAME'", "'NOW'", "'PERIOD_ADD'", + "'PERIOD_DIFF'", "'SEC_TO_TIME'", "'STR_TO_DATE'", "'SUBDATE'", + "'SUBTIME'", "'SYSDATE'", "'TIME'", "'TIMEDIFF'", "'TIMESTAMP'", + "'TIMESTAMPADD'", "'TIMESTAMPDIFF'", "'TIME_FORMAT'", "'TIME_TO_SEC'", + "'TO_DAYS'", "'TO_SECONDS'", "'UNIX_TIMESTAMP'", "'UTC_DATE'", "'UTC_TIME'", + "'UTC_TIMESTAMP'", "'WEEKDAY'", "'YEARWEEK'", "'SUBSTR'", "'SUBSTRING'", + "'LTRIM'", "'RTRIM'", "'TRIM'", "'TO'", "'LOWER'", "'UPPER'", "'CONCAT'", + "'CONCAT_WS'", "'LENGTH'", "'STRCMP'", "'RIGHT'", "'LEFT'", "'ASCII'", + "'LOCATE'", "'REPLACE'", "'REVERSE'", "'CAST'", "'LIKE'", "'ISNULL'", + "'ISNOTNULL'", "'IFNULL'", "'NULLIF'", "'IF'", "'TYPEOF'", "'MATCH'", + "'MATCH_PHRASE'", "'MATCH_PHRASE_PREFIX'", "'MATCH_BOOL_PREFIX'", + "'SIMPLE_QUERY_STRING'", "'MULTI_MATCH'", "'QUERY_STRING'", "'ALLOW_LEADING_WILDCARD'", + "'ANALYZE_WILDCARD'", "'ANALYZER'", "'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY'", + "'BOOST'", "'CUTOFF_FREQUENCY'", "'DEFAULT_FIELD'", "'DEFAULT_OPERATOR'", + "'ENABLE_POSITION_INCREMENTS'", "'ESCAPE'", "'FLAGS'", "'FUZZY_MAX_EXPANSIONS'", + "'FUZZY_PREFIX_LENGTH'", "'FUZZY_TRANSPOSITIONS'", "'FUZZY_REWRITE'", + "'FUZZINESS'", "'LENIENT'", "'LOW_FREQ_OPERATOR'", "'MAX_DETERMINIZED_STATES'", + "'MAX_EXPANSIONS'", "'MINIMUM_SHOULD_MATCH'", "'OPERATOR'", "'PHRASE_SLOP'", + "'PREFIX_LENGTH'", "'QUOTE_ANALYZER'", "'QUOTE_FIELD_SUFFIX'", "'REWRITE'", + "'SLOP'", "'TIE_BREAKER'", "'TYPE'", "'ZERO_TERMS_QUERY'", "'SPAN'", + "'MS'", "'S'", "'M'", "'H'", "'W'", "'Q'", "'Y'" + ]; + + public static readonly symbolicNames = [ + null, "SPACE", "SEARCH", "DESCRIBE", "SHOW", "FROM", "WHERE", "FIELDS", + "RENAME", "STATS", "DEDUP", "SORT", "EVAL", "HEAD", "TOP", "RARE", + "PARSE", "METHOD", "REGEX", "PUNCT", "GROK", "PATTERN", "PATTERNS", + "NEW_FIELD", "KMEANS", "AD", "ML", "AS", "BY", "SOURCE", "INDEX", + "D", "DESC", "DATASOURCES", "SORTBY", "AUTO", "STR", "IP", "NUM", + "KEEPEMPTY", "CONSECUTIVE", "DEDUP_SPLITVALUES", "PARTITIONS", "ALLNUM", + "DELIM", "CENTROIDS", "ITERATIONS", "DISTANCE_TYPE", "NUMBER_OF_TREES", + "SHINGLE_SIZE", "SAMPLE_SIZE", "OUTPUT_AFTER", "TIME_DECAY", "ANOMALY_RATE", + "CATEGORY_FIELD", "TIME_FIELD", "TIME_ZONE", "TRAINING_DATA_SIZE", + "ANOMALY_SCORE_THRESHOLD", "CASE", "IN", "NOT", "OR", "AND", "XOR", + "TRUE", "FALSE", "REGEXP", "CONVERT_TZ", "DATETIME", "DAY", "DAY_HOUR", + "DAY_MICROSECOND", "DAY_MINUTE", "DAY_OF_YEAR", "DAY_SECOND", "HOUR", + "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_OF_DAY", "HOUR_SECOND", + "INTERVAL", "MICROSECOND", "MILLISECOND", "MINUTE", "MINUTE_MICROSECOND", + "MINUTE_OF_DAY", "MINUTE_OF_HOUR", "MINUTE_SECOND", "MONTH", "MONTH_OF_YEAR", + "QUARTER", "SECOND", "SECOND_MICROSECOND", "SECOND_OF_MINUTE", "WEEK", + "WEEK_OF_YEAR", "YEAR", "YEAR_MONTH", "DATAMODEL", "LOOKUP", "SAVEDSEARCH", + "INT", "INTEGER", "DOUBLE", "LONG", "FLOAT", "STRING", "BOOLEAN", + "PIPE", "COMMA", "DOT", "EQUAL", "GREATER", "LESS", "NOT_GREATER", + "NOT_LESS", "NOT_EQUAL", "PLUS", "MINUS", "STAR", "DIVIDE", "MODULE", + "EXCLAMATION_SYMBOL", "COLON", "LT_PRTHS", "RT_PRTHS", "LT_SQR_PRTHS", + "RT_SQR_PRTHS", "SINGLE_QUOTE", "DOUBLE_QUOTE", "BACKTICK", "BIT_NOT_OP", + "BIT_AND_OP", "BIT_XOR_OP", "AVG", "COUNT", "DISTINCT_COUNT", "ESTDC", + "ESTDC_ERROR", "MAX", "MEAN", "MEDIAN", "MIN", "MODE", "RANGE", + "STDEV", "STDEVP", "SUM", "SUMSQ", "VAR_SAMP", "VAR_POP", "STDDEV_SAMP", + "STDDEV_POP", "PERCENTILE", "TAKE", "FIRST", "LAST", "LIST", "VALUES", + "EARLIEST", "EARLIEST_TIME", "LATEST", "LATEST_TIME", "PER_DAY", + "PER_HOUR", "PER_MINUTE", "PER_SECOND", "RATE", "SPARKLINE", "C", + "DC", "ABS", "CBRT", "CEIL", "CEILING", "CONV", "CRC32", "E", "EXP", + "FLOOR", "LN", "LOG", "LOG10", "LOG2", "MOD", "PI", "POSITION", + "POW", "POWER", "RAND", "ROUND", "SIGN", "SQRT", "TRUNCATE", "ACOS", + "ASIN", "ATAN", "ATAN2", "COS", "COT", "DEGREES", "RADIANS", "SIN", + "TAN", "ADDDATE", "ADDTIME", "CURDATE", "CURRENT_DATE", "CURRENT_TIME", + "CURRENT_TIMESTAMP", "CURTIME", "DATE", "DATEDIFF", "DATE_ADD", + "DATE_FORMAT", "DATE_SUB", "DAYNAME", "DAYOFMONTH", "DAYOFWEEK", + "DAYOFYEAR", "DAY_OF_MONTH", "DAY_OF_WEEK", "EXTRACT", "FROM_DAYS", + "FROM_UNIXTIME", "GET_FORMAT", "LAST_DAY", "LOCALTIME", "LOCALTIMESTAMP", + "MAKEDATE", "MAKETIME", "MONTHNAME", "NOW", "PERIOD_ADD", "PERIOD_DIFF", + "SEC_TO_TIME", "STR_TO_DATE", "SUBDATE", "SUBTIME", "SYSDATE", "TIME", + "TIMEDIFF", "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", "TIME_FORMAT", + "TIME_TO_SEC", "TO_DAYS", "TO_SECONDS", "UNIX_TIMESTAMP", "UTC_DATE", + "UTC_TIME", "UTC_TIMESTAMP", "WEEKDAY", "YEARWEEK", "SUBSTR", "SUBSTRING", + "LTRIM", "RTRIM", "TRIM", "TO", "LOWER", "UPPER", "CONCAT", "CONCAT_WS", + "LENGTH", "STRCMP", "RIGHT", "LEFT", "ASCII", "LOCATE", "REPLACE", + "REVERSE", "CAST", "LIKE", "ISNULL", "ISNOTNULL", "IFNULL", "NULLIF", + "IF", "TYPEOF", "MATCH", "MATCH_PHRASE", "MATCH_PHRASE_PREFIX", + "MATCH_BOOL_PREFIX", "SIMPLE_QUERY_STRING", "MULTI_MATCH", "QUERY_STRING", + "ALLOW_LEADING_WILDCARD", "ANALYZE_WILDCARD", "ANALYZER", "AUTO_GENERATE_SYNONYMS_PHRASE_QUERY", + "BOOST", "CUTOFF_FREQUENCY", "DEFAULT_FIELD", "DEFAULT_OPERATOR", + "ENABLE_POSITION_INCREMENTS", "ESCAPE", "FLAGS", "FUZZY_MAX_EXPANSIONS", + "FUZZY_PREFIX_LENGTH", "FUZZY_TRANSPOSITIONS", "FUZZY_REWRITE", + "FUZZINESS", "LENIENT", "LOW_FREQ_OPERATOR", "MAX_DETERMINIZED_STATES", + "MAX_EXPANSIONS", "MINIMUM_SHOULD_MATCH", "OPERATOR", "PHRASE_SLOP", + "PREFIX_LENGTH", "QUOTE_ANALYZER", "QUOTE_FIELD_SUFFIX", "REWRITE", + "SLOP", "TIE_BREAKER", "TYPE", "ZERO_TERMS_QUERY", "SPAN", "MS", + "S", "M", "H", "W", "Q", "Y", "ID", "CLUSTER", "INTEGER_LITERAL", + "DECIMAL_LITERAL", "ID_DATE_SUFFIX", "DQUOTA_STRING", "SQUOTA_STRING", + "BQUOTA_STRING", "ERROR_RECOGNITION" + ]; + + public static readonly modeNames = [ + "DEFAULT_MODE", + ]; + + public static readonly ruleNames = [ + "SPACE", "SEARCH", "DESCRIBE", "SHOW", "FROM", "WHERE", "FIELDS", + "RENAME", "STATS", "DEDUP", "SORT", "EVAL", "HEAD", "TOP", "RARE", + "PARSE", "METHOD", "REGEX", "PUNCT", "GROK", "PATTERN", "PATTERNS", + "NEW_FIELD", "KMEANS", "AD", "ML", "AS", "BY", "SOURCE", "INDEX", + "D", "DESC", "DATASOURCES", "SORTBY", "AUTO", "STR", "IP", "NUM", + "KEEPEMPTY", "CONSECUTIVE", "DEDUP_SPLITVALUES", "PARTITIONS", "ALLNUM", + "DELIM", "CENTROIDS", "ITERATIONS", "DISTANCE_TYPE", "NUMBER_OF_TREES", + "SHINGLE_SIZE", "SAMPLE_SIZE", "OUTPUT_AFTER", "TIME_DECAY", "ANOMALY_RATE", + "CATEGORY_FIELD", "TIME_FIELD", "TIME_ZONE", "TRAINING_DATA_SIZE", + "ANOMALY_SCORE_THRESHOLD", "CASE", "IN", "NOT", "OR", "AND", "XOR", + "TRUE", "FALSE", "REGEXP", "CONVERT_TZ", "DATETIME", "DAY", "DAY_HOUR", + "DAY_MICROSECOND", "DAY_MINUTE", "DAY_OF_YEAR", "DAY_SECOND", "HOUR", + "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_OF_DAY", "HOUR_SECOND", + "INTERVAL", "MICROSECOND", "MILLISECOND", "MINUTE", "MINUTE_MICROSECOND", + "MINUTE_OF_DAY", "MINUTE_OF_HOUR", "MINUTE_SECOND", "MONTH", "MONTH_OF_YEAR", + "QUARTER", "SECOND", "SECOND_MICROSECOND", "SECOND_OF_MINUTE", "WEEK", + "WEEK_OF_YEAR", "YEAR", "YEAR_MONTH", "DATAMODEL", "LOOKUP", "SAVEDSEARCH", + "INT", "INTEGER", "DOUBLE", "LONG", "FLOAT", "STRING", "BOOLEAN", + "PIPE", "COMMA", "DOT", "EQUAL", "GREATER", "LESS", "NOT_GREATER", + "NOT_LESS", "NOT_EQUAL", "PLUS", "MINUS", "STAR", "DIVIDE", "MODULE", + "EXCLAMATION_SYMBOL", "COLON", "LT_PRTHS", "RT_PRTHS", "LT_SQR_PRTHS", + "RT_SQR_PRTHS", "SINGLE_QUOTE", "DOUBLE_QUOTE", "BACKTICK", "BIT_NOT_OP", + "BIT_AND_OP", "BIT_XOR_OP", "AVG", "COUNT", "DISTINCT_COUNT", "ESTDC", + "ESTDC_ERROR", "MAX", "MEAN", "MEDIAN", "MIN", "MODE", "RANGE", + "STDEV", "STDEVP", "SUM", "SUMSQ", "VAR_SAMP", "VAR_POP", "STDDEV_SAMP", + "STDDEV_POP", "PERCENTILE", "TAKE", "FIRST", "LAST", "LIST", "VALUES", + "EARLIEST", "EARLIEST_TIME", "LATEST", "LATEST_TIME", "PER_DAY", + "PER_HOUR", "PER_MINUTE", "PER_SECOND", "RATE", "SPARKLINE", "C", + "DC", "ABS", "CBRT", "CEIL", "CEILING", "CONV", "CRC32", "E", "EXP", + "FLOOR", "LN", "LOG", "LOG10", "LOG2", "MOD", "PI", "POSITION", + "POW", "POWER", "RAND", "ROUND", "SIGN", "SQRT", "TRUNCATE", "ACOS", + "ASIN", "ATAN", "ATAN2", "COS", "COT", "DEGREES", "RADIANS", "SIN", + "TAN", "ADDDATE", "ADDTIME", "CURDATE", "CURRENT_DATE", "CURRENT_TIME", + "CURRENT_TIMESTAMP", "CURTIME", "DATE", "DATEDIFF", "DATE_ADD", + "DATE_FORMAT", "DATE_SUB", "DAYNAME", "DAYOFMONTH", "DAYOFWEEK", + "DAYOFYEAR", "DAY_OF_MONTH", "DAY_OF_WEEK", "EXTRACT", "FROM_DAYS", + "FROM_UNIXTIME", "GET_FORMAT", "LAST_DAY", "LOCALTIME", "LOCALTIMESTAMP", + "MAKEDATE", "MAKETIME", "MONTHNAME", "NOW", "PERIOD_ADD", "PERIOD_DIFF", + "SEC_TO_TIME", "STR_TO_DATE", "SUBDATE", "SUBTIME", "SYSDATE", "TIME", + "TIMEDIFF", "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", "TIME_FORMAT", + "TIME_TO_SEC", "TO_DAYS", "TO_SECONDS", "UNIX_TIMESTAMP", "UTC_DATE", + "UTC_TIME", "UTC_TIMESTAMP", "WEEKDAY", "YEARWEEK", "SUBSTR", "SUBSTRING", + "LTRIM", "RTRIM", "TRIM", "TO", "LOWER", "UPPER", "CONCAT", "CONCAT_WS", + "LENGTH", "STRCMP", "RIGHT", "LEFT", "ASCII", "LOCATE", "REPLACE", + "REVERSE", "CAST", "LIKE", "ISNULL", "ISNOTNULL", "IFNULL", "NULLIF", + "IF", "TYPEOF", "MATCH", "MATCH_PHRASE", "MATCH_PHRASE_PREFIX", + "MATCH_BOOL_PREFIX", "SIMPLE_QUERY_STRING", "MULTI_MATCH", "QUERY_STRING", + "ALLOW_LEADING_WILDCARD", "ANALYZE_WILDCARD", "ANALYZER", "AUTO_GENERATE_SYNONYMS_PHRASE_QUERY", + "BOOST", "CUTOFF_FREQUENCY", "DEFAULT_FIELD", "DEFAULT_OPERATOR", + "ENABLE_POSITION_INCREMENTS", "ESCAPE", "FLAGS", "FUZZY_MAX_EXPANSIONS", + "FUZZY_PREFIX_LENGTH", "FUZZY_TRANSPOSITIONS", "FUZZY_REWRITE", + "FUZZINESS", "LENIENT", "LOW_FREQ_OPERATOR", "MAX_DETERMINIZED_STATES", + "MAX_EXPANSIONS", "MINIMUM_SHOULD_MATCH", "OPERATOR", "PHRASE_SLOP", + "PREFIX_LENGTH", "QUOTE_ANALYZER", "QUOTE_FIELD_SUFFIX", "REWRITE", + "SLOP", "TIE_BREAKER", "TYPE", "ZERO_TERMS_QUERY", "SPAN", "MS", + "S", "M", "H", "W", "Q", "Y", "ID", "CLUSTER", "INTEGER_LITERAL", + "DECIMAL_LITERAL", "DATE_SUFFIX", "ID_LITERAL", "CLUSTER_PREFIX_LITERAL", + "ID_DATE_SUFFIX", "DQUOTA_STRING", "SQUOTA_STRING", "BQUOTA_STRING", + "DEC_DIGIT", "ERROR_RECOGNITION", + ]; + + + public constructor(input: antlr.CharStream) { + super(input); + this.interpreter = new antlr.LexerATNSimulator(this, OpenSearchPPLLexer._ATN, OpenSearchPPLLexer.decisionsToDFA, new antlr.PredictionContextCache()); + } + + public get grammarFileName(): string { return "OpenSearchPPLLexer.g4"; } + + public get literalNames(): (string | null)[] { return OpenSearchPPLLexer.literalNames; } + public get symbolicNames(): (string | null)[] { return OpenSearchPPLLexer.symbolicNames; } + public get ruleNames(): string[] { return OpenSearchPPLLexer.ruleNames; } + + public get serializedATN(): number[] { return OpenSearchPPLLexer._serializedATN; } + + public get channelNames(): string[] { return OpenSearchPPLLexer.channelNames; } + + public get modeNames(): string[] { return OpenSearchPPLLexer.modeNames; } + + public static readonly _serializedATN: number[] = [ + 4,0,336,3509,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7, + 5,2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12, + 2,13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19, + 7,19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25, + 2,26,7,26,2,27,7,27,2,28,7,28,2,29,7,29,2,30,7,30,2,31,7,31,2,32, + 7,32,2,33,7,33,2,34,7,34,2,35,7,35,2,36,7,36,2,37,7,37,2,38,7,38, + 2,39,7,39,2,40,7,40,2,41,7,41,2,42,7,42,2,43,7,43,2,44,7,44,2,45, + 7,45,2,46,7,46,2,47,7,47,2,48,7,48,2,49,7,49,2,50,7,50,2,51,7,51, + 2,52,7,52,2,53,7,53,2,54,7,54,2,55,7,55,2,56,7,56,2,57,7,57,2,58, + 7,58,2,59,7,59,2,60,7,60,2,61,7,61,2,62,7,62,2,63,7,63,2,64,7,64, + 2,65,7,65,2,66,7,66,2,67,7,67,2,68,7,68,2,69,7,69,2,70,7,70,2,71, + 7,71,2,72,7,72,2,73,7,73,2,74,7,74,2,75,7,75,2,76,7,76,2,77,7,77, + 2,78,7,78,2,79,7,79,2,80,7,80,2,81,7,81,2,82,7,82,2,83,7,83,2,84, + 7,84,2,85,7,85,2,86,7,86,2,87,7,87,2,88,7,88,2,89,7,89,2,90,7,90, + 2,91,7,91,2,92,7,92,2,93,7,93,2,94,7,94,2,95,7,95,2,96,7,96,2,97, + 7,97,2,98,7,98,2,99,7,99,2,100,7,100,2,101,7,101,2,102,7,102,2,103, + 7,103,2,104,7,104,2,105,7,105,2,106,7,106,2,107,7,107,2,108,7,108, + 2,109,7,109,2,110,7,110,2,111,7,111,2,112,7,112,2,113,7,113,2,114, + 7,114,2,115,7,115,2,116,7,116,2,117,7,117,2,118,7,118,2,119,7,119, + 2,120,7,120,2,121,7,121,2,122,7,122,2,123,7,123,2,124,7,124,2,125, + 7,125,2,126,7,126,2,127,7,127,2,128,7,128,2,129,7,129,2,130,7,130, + 2,131,7,131,2,132,7,132,2,133,7,133,2,134,7,134,2,135,7,135,2,136, + 7,136,2,137,7,137,2,138,7,138,2,139,7,139,2,140,7,140,2,141,7,141, + 2,142,7,142,2,143,7,143,2,144,7,144,2,145,7,145,2,146,7,146,2,147, + 7,147,2,148,7,148,2,149,7,149,2,150,7,150,2,151,7,151,2,152,7,152, + 2,153,7,153,2,154,7,154,2,155,7,155,2,156,7,156,2,157,7,157,2,158, + 7,158,2,159,7,159,2,160,7,160,2,161,7,161,2,162,7,162,2,163,7,163, + 2,164,7,164,2,165,7,165,2,166,7,166,2,167,7,167,2,168,7,168,2,169, + 7,169,2,170,7,170,2,171,7,171,2,172,7,172,2,173,7,173,2,174,7,174, + 2,175,7,175,2,176,7,176,2,177,7,177,2,178,7,178,2,179,7,179,2,180, + 7,180,2,181,7,181,2,182,7,182,2,183,7,183,2,184,7,184,2,185,7,185, + 2,186,7,186,2,187,7,187,2,188,7,188,2,189,7,189,2,190,7,190,2,191, + 7,191,2,192,7,192,2,193,7,193,2,194,7,194,2,195,7,195,2,196,7,196, + 2,197,7,197,2,198,7,198,2,199,7,199,2,200,7,200,2,201,7,201,2,202, + 7,202,2,203,7,203,2,204,7,204,2,205,7,205,2,206,7,206,2,207,7,207, + 2,208,7,208,2,209,7,209,2,210,7,210,2,211,7,211,2,212,7,212,2,213, + 7,213,2,214,7,214,2,215,7,215,2,216,7,216,2,217,7,217,2,218,7,218, + 2,219,7,219,2,220,7,220,2,221,7,221,2,222,7,222,2,223,7,223,2,224, + 7,224,2,225,7,225,2,226,7,226,2,227,7,227,2,228,7,228,2,229,7,229, + 2,230,7,230,2,231,7,231,2,232,7,232,2,233,7,233,2,234,7,234,2,235, + 7,235,2,236,7,236,2,237,7,237,2,238,7,238,2,239,7,239,2,240,7,240, + 2,241,7,241,2,242,7,242,2,243,7,243,2,244,7,244,2,245,7,245,2,246, + 7,246,2,247,7,247,2,248,7,248,2,249,7,249,2,250,7,250,2,251,7,251, + 2,252,7,252,2,253,7,253,2,254,7,254,2,255,7,255,2,256,7,256,2,257, + 7,257,2,258,7,258,2,259,7,259,2,260,7,260,2,261,7,261,2,262,7,262, + 2,263,7,263,2,264,7,264,2,265,7,265,2,266,7,266,2,267,7,267,2,268, + 7,268,2,269,7,269,2,270,7,270,2,271,7,271,2,272,7,272,2,273,7,273, + 2,274,7,274,2,275,7,275,2,276,7,276,2,277,7,277,2,278,7,278,2,279, + 7,279,2,280,7,280,2,281,7,281,2,282,7,282,2,283,7,283,2,284,7,284, + 2,285,7,285,2,286,7,286,2,287,7,287,2,288,7,288,2,289,7,289,2,290, + 7,290,2,291,7,291,2,292,7,292,2,293,7,293,2,294,7,294,2,295,7,295, + 2,296,7,296,2,297,7,297,2,298,7,298,2,299,7,299,2,300,7,300,2,301, + 7,301,2,302,7,302,2,303,7,303,2,304,7,304,2,305,7,305,2,306,7,306, + 2,307,7,307,2,308,7,308,2,309,7,309,2,310,7,310,2,311,7,311,2,312, + 7,312,2,313,7,313,2,314,7,314,2,315,7,315,2,316,7,316,2,317,7,317, + 2,318,7,318,2,319,7,319,2,320,7,320,2,321,7,321,2,322,7,322,2,323, + 7,323,2,324,7,324,2,325,7,325,2,326,7,326,2,327,7,327,2,328,7,328, + 2,329,7,329,2,330,7,330,2,331,7,331,2,332,7,332,2,333,7,333,2,334, + 7,334,2,335,7,335,2,336,7,336,2,337,7,337,2,338,7,338,2,339,7,339, + 1,0,4,0,683,8,0,11,0,12,0,684,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,3,1,4,1, + 4,1,4,1,4,1,4,1,5,1,5,1,5,1,5,1,5,1,5,1,6,1,6,1,6,1,6,1,6,1,6,1, + 6,1,7,1,7,1,7,1,7,1,7,1,7,1,7,1,8,1,8,1,8,1,8,1,8,1,8,1,9,1,9,1, + 9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10,1,11,1,11,1,11,1,11,1,11, + 1,12,1,12,1,12,1,12,1,12,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,14, + 1,14,1,15,1,15,1,15,1,15,1,15,1,15,1,16,1,16,1,16,1,16,1,16,1,16, + 1,16,1,17,1,17,1,17,1,17,1,17,1,17,1,18,1,18,1,18,1,18,1,18,1,18, + 1,19,1,19,1,19,1,19,1,19,1,20,1,20,1,20,1,20,1,20,1,20,1,20,1,20, + 1,21,1,21,1,21,1,21,1,21,1,21,1,21,1,21,1,21,1,22,1,22,1,22,1,22, + 1,22,1,22,1,22,1,22,1,22,1,22,1,23,1,23,1,23,1,23,1,23,1,23,1,23, + 1,24,1,24,1,24,1,25,1,25,1,25,1,26,1,26,1,26,1,27,1,27,1,27,1,28, + 1,28,1,28,1,28,1,28,1,28,1,28,1,29,1,29,1,29,1,29,1,29,1,29,1,30, + 1,30,1,31,1,31,1,31,1,31,1,31,1,32,1,32,1,32,1,32,1,32,1,32,1,32, + 1,32,1,32,1,32,1,32,1,32,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,34, + 1,34,1,34,1,34,1,34,1,35,1,35,1,35,1,35,1,36,1,36,1,36,1,37,1,37, + 1,37,1,37,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,38,1,39, + 1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,39,1,40,1,40, + 1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40, + 1,40,1,40,1,40,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41,1,41, + 1,41,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,43,1,43,1,43,1,43,1,43, + 1,43,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,45,1,45, + 1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,46,1,46,1,46,1,46, + 1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,47,1,47,1,47, + 1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47, + 1,48,1,48,1,48,1,48,1,48,1,48,1,48,1,48,1,48,1,48,1,48,1,48,1,48, + 1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,49,1,50, + 1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,51, + 1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,51,1,52,1,52,1,52, + 1,52,1,52,1,52,1,52,1,52,1,52,1,52,1,52,1,52,1,52,1,53,1,53,1,53, + 1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,54, + 1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,54,1,55,1,55,1,55, + 1,55,1,55,1,55,1,55,1,55,1,55,1,55,1,56,1,56,1,56,1,56,1,56,1,56, + 1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56, + 1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57, + 1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,58,1,58, + 1,58,1,58,1,58,1,59,1,59,1,59,1,60,1,60,1,60,1,60,1,61,1,61,1,61, + 1,62,1,62,1,62,1,62,1,63,1,63,1,63,1,63,1,64,1,64,1,64,1,64,1,64, + 1,65,1,65,1,65,1,65,1,65,1,65,1,66,1,66,1,66,1,66,1,66,1,66,1,66, + 1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,68,1,68, + 1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,69,1,69,1,69,1,69,1,70,1,70, + 1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,71,1,71,1,71,1,71,1,71,1,71, + 1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,72,1,72,1,72, + 1,72,1,72,1,72,1,72,1,72,1,72,1,72,1,72,1,73,1,73,1,73,1,73,1,73, + 1,73,1,73,1,73,1,73,1,73,1,73,1,73,1,74,1,74,1,74,1,74,1,74,1,74, + 1,74,1,74,1,74,1,74,1,74,1,75,1,75,1,75,1,75,1,75,1,76,1,76,1,76, + 1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76, + 1,76,1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,77,1,77, + 1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,78,1,79, + 1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,80,1,80, + 1,80,1,80,1,80,1,80,1,80,1,80,1,80,1,81,1,81,1,81,1,81,1,81,1,81, + 1,81,1,81,1,81,1,81,1,81,1,81,1,82,1,82,1,82,1,82,1,82,1,82,1,82, + 1,82,1,82,1,82,1,82,1,82,1,83,1,83,1,83,1,83,1,83,1,83,1,83,1,84, + 1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84, + 1,84,1,84,1,84,1,84,1,84,1,85,1,85,1,85,1,85,1,85,1,85,1,85,1,85, + 1,85,1,85,1,85,1,85,1,85,1,85,1,86,1,86,1,86,1,86,1,86,1,86,1,86, + 1,86,1,86,1,86,1,86,1,86,1,86,1,86,1,86,1,87,1,87,1,87,1,87,1,87, + 1,87,1,87,1,87,1,87,1,87,1,87,1,87,1,87,1,87,1,88,1,88,1,88,1,88, + 1,88,1,88,1,89,1,89,1,89,1,89,1,89,1,89,1,89,1,89,1,89,1,89,1,89, + 1,89,1,89,1,89,1,90,1,90,1,90,1,90,1,90,1,90,1,90,1,90,1,91,1,91, + 1,91,1,91,1,91,1,91,1,91,1,92,1,92,1,92,1,92,1,92,1,92,1,92,1,92, + 1,92,1,92,1,92,1,92,1,92,1,92,1,92,1,92,1,92,1,92,1,92,1,93,1,93, + 1,93,1,93,1,93,1,93,1,93,1,93,1,93,1,93,1,93,1,93,1,93,1,93,1,93, + 1,93,1,93,1,94,1,94,1,94,1,94,1,94,1,95,1,95,1,95,1,95,1,95,1,95, + 1,95,1,95,1,95,1,95,1,95,1,95,1,95,1,96,1,96,1,96,1,96,1,96,1,97, + 1,97,1,97,1,97,1,97,1,97,1,97,1,97,1,97,1,97,1,97,1,98,1,98,1,98, + 1,98,1,98,1,98,1,98,1,98,1,98,1,98,1,99,1,99,1,99,1,99,1,99,1,99, + 1,99,1,100,1,100,1,100,1,100,1,100,1,100,1,100,1,100,1,100,1,100, + 1,100,1,100,1,101,1,101,1,101,1,101,1,102,1,102,1,102,1,102,1,102, + 1,102,1,102,1,102,1,103,1,103,1,103,1,103,1,103,1,103,1,103,1,104, + 1,104,1,104,1,104,1,104,1,105,1,105,1,105,1,105,1,105,1,105,1,106, + 1,106,1,106,1,106,1,106,1,106,1,106,1,107,1,107,1,107,1,107,1,107, + 1,107,1,107,1,107,1,108,1,108,1,109,1,109,1,110,1,110,1,111,1,111, + 1,112,1,112,1,113,1,113,1,114,1,114,1,114,1,115,1,115,1,115,1,116, + 1,116,1,116,1,117,1,117,1,118,1,118,1,119,1,119,1,120,1,120,1,121, + 1,121,1,122,1,122,1,123,1,123,1,124,1,124,1,125,1,125,1,126,1,126, + 1,127,1,127,1,128,1,128,1,129,1,129,1,130,1,130,1,131,1,131,1,132, + 1,132,1,133,1,133,1,134,1,134,1,134,1,134,1,135,1,135,1,135,1,135, + 1,135,1,135,1,136,1,136,1,136,1,136,1,136,1,136,1,136,1,136,1,136, + 1,136,1,136,1,136,1,136,1,136,1,136,1,137,1,137,1,137,1,137,1,137, + 1,137,1,138,1,138,1,138,1,138,1,138,1,138,1,138,1,138,1,138,1,138, + 1,138,1,138,1,139,1,139,1,139,1,139,1,140,1,140,1,140,1,140,1,140, + 1,141,1,141,1,141,1,141,1,141,1,141,1,141,1,142,1,142,1,142,1,142, + 1,143,1,143,1,143,1,143,1,143,1,144,1,144,1,144,1,144,1,144,1,144, + 1,145,1,145,1,145,1,145,1,145,1,145,1,146,1,146,1,146,1,146,1,146, + 1,146,1,146,1,147,1,147,1,147,1,147,1,148,1,148,1,148,1,148,1,148, + 1,148,1,149,1,149,1,149,1,149,1,149,1,149,1,149,1,149,1,149,1,150, + 1,150,1,150,1,150,1,150,1,150,1,150,1,150,1,151,1,151,1,151,1,151, + 1,151,1,151,1,151,1,151,1,151,1,151,1,151,1,151,1,152,1,152,1,152, + 1,152,1,152,1,152,1,152,1,152,1,152,1,152,1,152,1,153,1,153,1,153, + 1,153,1,153,1,153,1,153,1,153,1,153,1,153,1,153,1,154,1,154,1,154, + 1,154,1,154,1,155,1,155,1,155,1,155,1,155,1,155,1,156,1,156,1,156, + 1,156,1,156,1,157,1,157,1,157,1,157,1,157,1,158,1,158,1,158,1,158, + 1,158,1,158,1,158,1,159,1,159,1,159,1,159,1,159,1,159,1,159,1,159, + 1,159,1,160,1,160,1,160,1,160,1,160,1,160,1,160,1,160,1,160,1,160, + 1,160,1,160,1,160,1,160,1,161,1,161,1,161,1,161,1,161,1,161,1,161, + 1,162,1,162,1,162,1,162,1,162,1,162,1,162,1,162,1,162,1,162,1,162, + 1,162,1,163,1,163,1,163,1,163,1,163,1,163,1,163,1,163,1,164,1,164, + 1,164,1,164,1,164,1,164,1,164,1,164,1,164,1,165,1,165,1,165,1,165, + 1,165,1,165,1,165,1,165,1,165,1,165,1,165,1,166,1,166,1,166,1,166, + 1,166,1,166,1,166,1,166,1,166,1,166,1,166,1,167,1,167,1,167,1,167, + 1,167,1,168,1,168,1,168,1,168,1,168,1,168,1,168,1,168,1,168,1,168, + 1,169,1,169,1,170,1,170,1,170,1,171,1,171,1,171,1,171,1,172,1,172, + 1,172,1,172,1,172,1,173,1,173,1,173,1,173,1,173,1,174,1,174,1,174, + 1,174,1,174,1,174,1,174,1,174,1,175,1,175,1,175,1,175,1,175,1,176, + 1,176,1,176,1,176,1,176,1,176,1,177,1,177,1,178,1,178,1,178,1,178, + 1,179,1,179,1,179,1,179,1,179,1,179,1,180,1,180,1,180,1,181,1,181, + 1,181,1,181,1,182,1,182,1,182,1,182,1,182,1,182,1,183,1,183,1,183, + 1,183,1,183,1,184,1,184,1,184,1,184,1,185,1,185,1,185,1,186,1,186, + 1,186,1,186,1,186,1,186,1,186,1,186,1,186,1,187,1,187,1,187,1,187, + 1,188,1,188,1,188,1,188,1,188,1,188,1,189,1,189,1,189,1,189,1,189, + 1,190,1,190,1,190,1,190,1,190,1,190,1,191,1,191,1,191,1,191,1,191, + 1,192,1,192,1,192,1,192,1,192,1,193,1,193,1,193,1,193,1,193,1,193, + 1,193,1,193,1,193,1,194,1,194,1,194,1,194,1,194,1,195,1,195,1,195, + 1,195,1,195,1,196,1,196,1,196,1,196,1,196,1,197,1,197,1,197,1,197, + 1,197,1,197,1,198,1,198,1,198,1,198,1,199,1,199,1,199,1,199,1,200, + 1,200,1,200,1,200,1,200,1,200,1,200,1,200,1,201,1,201,1,201,1,201, + 1,201,1,201,1,201,1,201,1,202,1,202,1,202,1,202,1,203,1,203,1,203, + 1,203,1,204,1,204,1,204,1,204,1,204,1,204,1,204,1,204,1,205,1,205, + 1,205,1,205,1,205,1,205,1,205,1,205,1,206,1,206,1,206,1,206,1,206, + 1,206,1,206,1,206,1,207,1,207,1,207,1,207,1,207,1,207,1,207,1,207, + 1,207,1,207,1,207,1,207,1,207,1,208,1,208,1,208,1,208,1,208,1,208, + 1,208,1,208,1,208,1,208,1,208,1,208,1,208,1,209,1,209,1,209,1,209, + 1,209,1,209,1,209,1,209,1,209,1,209,1,209,1,209,1,209,1,209,1,209, + 1,209,1,209,1,209,1,210,1,210,1,210,1,210,1,210,1,210,1,210,1,210, + 1,211,1,211,1,211,1,211,1,211,1,212,1,212,1,212,1,212,1,212,1,212, + 1,212,1,212,1,212,1,213,1,213,1,213,1,213,1,213,1,213,1,213,1,213, + 1,213,1,214,1,214,1,214,1,214,1,214,1,214,1,214,1,214,1,214,1,214, + 1,214,1,214,1,215,1,215,1,215,1,215,1,215,1,215,1,215,1,215,1,215, + 1,216,1,216,1,216,1,216,1,216,1,216,1,216,1,216,1,217,1,217,1,217, + 1,217,1,217,1,217,1,217,1,217,1,217,1,217,1,217,1,218,1,218,1,218, + 1,218,1,218,1,218,1,218,1,218,1,218,1,218,1,219,1,219,1,219,1,219, + 1,219,1,219,1,219,1,219,1,219,1,219,1,220,1,220,1,220,1,220,1,220, + 1,220,1,220,1,220,1,220,1,220,1,220,1,220,1,220,1,221,1,221,1,221, + 1,221,1,221,1,221,1,221,1,221,1,221,1,221,1,221,1,221,1,222,1,222, + 1,222,1,222,1,222,1,222,1,222,1,222,1,223,1,223,1,223,1,223,1,223, + 1,223,1,223,1,223,1,223,1,223,1,224,1,224,1,224,1,224,1,224,1,224, + 1,224,1,224,1,224,1,224,1,224,1,224,1,224,1,224,1,225,1,225,1,225, + 1,225,1,225,1,225,1,225,1,225,1,225,1,225,1,225,1,226,1,226,1,226, + 1,226,1,226,1,226,1,226,1,226,1,226,1,227,1,227,1,227,1,227,1,227, + 1,227,1,227,1,227,1,227,1,227,1,228,1,228,1,228,1,228,1,228,1,228, + 1,228,1,228,1,228,1,228,1,228,1,228,1,228,1,228,1,228,1,229,1,229, + 1,229,1,229,1,229,1,229,1,229,1,229,1,229,1,230,1,230,1,230,1,230, + 1,230,1,230,1,230,1,230,1,230,1,231,1,231,1,231,1,231,1,231,1,231, + 1,231,1,231,1,231,1,231,1,232,1,232,1,232,1,232,1,233,1,233,1,233, + 1,233,1,233,1,233,1,233,1,233,1,233,1,233,1,233,1,234,1,234,1,234, + 1,234,1,234,1,234,1,234,1,234,1,234,1,234,1,234,1,234,1,235,1,235, + 1,235,1,235,1,235,1,235,1,235,1,235,1,235,1,235,1,235,1,235,1,236, + 1,236,1,236,1,236,1,236,1,236,1,236,1,236,1,236,1,236,1,236,1,236, + 1,237,1,237,1,237,1,237,1,237,1,237,1,237,1,237,1,238,1,238,1,238, + 1,238,1,238,1,238,1,238,1,238,1,239,1,239,1,239,1,239,1,239,1,239, + 1,239,1,239,1,240,1,240,1,240,1,240,1,240,1,241,1,241,1,241,1,241, + 1,241,1,241,1,241,1,241,1,241,1,242,1,242,1,242,1,242,1,242,1,242, + 1,242,1,242,1,242,1,242,1,243,1,243,1,243,1,243,1,243,1,243,1,243, + 1,243,1,243,1,243,1,243,1,243,1,243,1,244,1,244,1,244,1,244,1,244, + 1,244,1,244,1,244,1,244,1,244,1,244,1,244,1,244,1,244,1,245,1,245, + 1,245,1,245,1,245,1,245,1,245,1,245,1,245,1,245,1,245,1,245,1,246, + 1,246,1,246,1,246,1,246,1,246,1,246,1,246,1,246,1,246,1,246,1,246, + 1,247,1,247,1,247,1,247,1,247,1,247,1,247,1,247,1,248,1,248,1,248, + 1,248,1,248,1,248,1,248,1,248,1,248,1,248,1,248,1,249,1,249,1,249, + 1,249,1,249,1,249,1,249,1,249,1,249,1,249,1,249,1,249,1,249,1,249, + 1,249,1,250,1,250,1,250,1,250,1,250,1,250,1,250,1,250,1,250,1,251, + 1,251,1,251,1,251,1,251,1,251,1,251,1,251,1,251,1,252,1,252,1,252, + 1,252,1,252,1,252,1,252,1,252,1,252,1,252,1,252,1,252,1,252,1,252, + 1,253,1,253,1,253,1,253,1,253,1,253,1,253,1,253,1,254,1,254,1,254, + 1,254,1,254,1,254,1,254,1,254,1,254,1,255,1,255,1,255,1,255,1,255, + 1,255,1,255,1,256,1,256,1,256,1,256,1,256,1,256,1,256,1,256,1,256, + 1,256,1,257,1,257,1,257,1,257,1,257,1,257,1,258,1,258,1,258,1,258, + 1,258,1,258,1,259,1,259,1,259,1,259,1,259,1,260,1,260,1,260,1,261, + 1,261,1,261,1,261,1,261,1,261,1,262,1,262,1,262,1,262,1,262,1,262, + 1,263,1,263,1,263,1,263,1,263,1,263,1,263,1,264,1,264,1,264,1,264, + 1,264,1,264,1,264,1,264,1,264,1,264,1,265,1,265,1,265,1,265,1,265, + 1,265,1,265,1,266,1,266,1,266,1,266,1,266,1,266,1,266,1,267,1,267, + 1,267,1,267,1,267,1,267,1,268,1,268,1,268,1,268,1,268,1,269,1,269, + 1,269,1,269,1,269,1,269,1,270,1,270,1,270,1,270,1,270,1,270,1,270, + 1,271,1,271,1,271,1,271,1,271,1,271,1,271,1,271,1,272,1,272,1,272, + 1,272,1,272,1,272,1,272,1,272,1,273,1,273,1,273,1,273,1,273,1,274, + 1,274,1,274,1,274,1,274,1,275,1,275,1,275,1,275,1,275,1,275,1,275, + 1,276,1,276,1,276,1,276,1,276,1,276,1,276,1,276,1,276,1,276,1,277, + 1,277,1,277,1,277,1,277,1,277,1,277,1,278,1,278,1,278,1,278,1,278, + 1,278,1,278,1,279,1,279,1,279,1,280,1,280,1,280,1,280,1,280,1,280, + 1,280,1,281,1,281,1,281,1,281,1,281,1,281,1,282,1,282,1,282,1,282, + 1,282,1,282,1,282,1,282,1,282,1,282,1,282,1,282,1,282,1,283,1,283, + 1,283,1,283,1,283,1,283,1,283,1,283,1,283,1,283,1,283,1,283,1,283, + 1,283,1,283,1,283,1,283,1,283,1,283,1,283,1,284,1,284,1,284,1,284, + 1,284,1,284,1,284,1,284,1,284,1,284,1,284,1,284,1,284,1,284,1,284, + 1,284,1,284,1,284,1,285,1,285,1,285,1,285,1,285,1,285,1,285,1,285, + 1,285,1,285,1,285,1,285,1,285,1,285,1,285,1,285,1,285,1,285,1,285, + 1,285,1,286,1,286,1,286,1,286,1,286,1,286,1,286,1,286,1,286,1,286, + 1,286,1,286,1,287,1,287,1,287,1,287,1,287,1,287,1,287,1,287,1,287, + 1,287,1,287,1,287,1,287,1,288,1,288,1,288,1,288,1,288,1,288,1,288, + 1,288,1,288,1,288,1,288,1,288,1,288,1,288,1,288,1,288,1,288,1,288, + 1,288,1,288,1,288,1,288,1,288,1,289,1,289,1,289,1,289,1,289,1,289, + 1,289,1,289,1,289,1,289,1,289,1,289,1,289,1,289,1,289,1,289,1,289, + 1,290,1,290,1,290,1,290,1,290,1,290,1,290,1,290,1,290,1,291,1,291, + 1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291, + 1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291, + 1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291,1,291, + 1,291,1,292,1,292,1,292,1,292,1,292,1,292,1,293,1,293,1,293,1,293, + 1,293,1,293,1,293,1,293,1,293,1,293,1,293,1,293,1,293,1,293,1,293, + 1,293,1,293,1,294,1,294,1,294,1,294,1,294,1,294,1,294,1,294,1,294, + 1,294,1,294,1,294,1,294,1,294,1,295,1,295,1,295,1,295,1,295,1,295, + 1,295,1,295,1,295,1,295,1,295,1,295,1,295,1,295,1,295,1,295,1,295, + 1,296,1,296,1,296,1,296,1,296,1,296,1,296,1,296,1,296,1,296,1,296, + 1,296,1,296,1,296,1,296,1,296,1,296,1,296,1,296,1,296,1,296,1,296, + 1,296,1,296,1,296,1,296,1,296,1,297,1,297,1,297,1,297,1,297,1,297, + 1,297,1,298,1,298,1,298,1,298,1,298,1,298,1,299,1,299,1,299,1,299, + 1,299,1,299,1,299,1,299,1,299,1,299,1,299,1,299,1,299,1,299,1,299, + 1,299,1,299,1,299,1,299,1,299,1,299,1,300,1,300,1,300,1,300,1,300, + 1,300,1,300,1,300,1,300,1,300,1,300,1,300,1,300,1,300,1,300,1,300, + 1,300,1,300,1,300,1,300,1,301,1,301,1,301,1,301,1,301,1,301,1,301, + 1,301,1,301,1,301,1,301,1,301,1,301,1,301,1,301,1,301,1,301,1,301, + 1,301,1,301,1,301,1,302,1,302,1,302,1,302,1,302,1,302,1,302,1,302, + 1,302,1,302,1,302,1,302,1,302,1,302,1,303,1,303,1,303,1,303,1,303, + 1,303,1,303,1,303,1,303,1,303,1,304,1,304,1,304,1,304,1,304,1,304, + 1,304,1,304,1,305,1,305,1,305,1,305,1,305,1,305,1,305,1,305,1,305, + 1,305,1,305,1,305,1,305,1,305,1,305,1,305,1,305,1,305,1,306,1,306, + 1,306,1,306,1,306,1,306,1,306,1,306,1,306,1,306,1,306,1,306,1,306, + 1,306,1,306,1,306,1,306,1,306,1,306,1,306,1,306,1,306,1,306,1,306, + 1,307,1,307,1,307,1,307,1,307,1,307,1,307,1,307,1,307,1,307,1,307, + 1,307,1,307,1,307,1,307,1,308,1,308,1,308,1,308,1,308,1,308,1,308, + 1,308,1,308,1,308,1,308,1,308,1,308,1,308,1,308,1,308,1,308,1,308, + 1,308,1,308,1,308,1,309,1,309,1,309,1,309,1,309,1,309,1,309,1,309, + 1,309,1,310,1,310,1,310,1,310,1,310,1,310,1,310,1,310,1,310,1,310, + 1,310,1,310,1,311,1,311,1,311,1,311,1,311,1,311,1,311,1,311,1,311, + 1,311,1,311,1,311,1,311,1,311,1,312,1,312,1,312,1,312,1,312,1,312, + 1,312,1,312,1,312,1,312,1,312,1,312,1,312,1,312,1,312,1,313,1,313, + 1,313,1,313,1,313,1,313,1,313,1,313,1,313,1,313,1,313,1,313,1,313, + 1,313,1,313,1,313,1,313,1,313,1,313,1,314,1,314,1,314,1,314,1,314, + 1,314,1,314,1,314,1,315,1,315,1,315,1,315,1,315,1,316,1,316,1,316, + 1,316,1,316,1,316,1,316,1,316,1,316,1,316,1,316,1,316,1,317,1,317, + 1,317,1,317,1,317,1,318,1,318,1,318,1,318,1,318,1,318,1,318,1,318, + 1,318,1,318,1,318,1,318,1,318,1,318,1,318,1,318,1,318,1,319,1,319, + 1,319,1,319,1,319,1,320,1,320,1,320,1,321,1,321,1,322,1,322,1,323, + 1,323,1,324,1,324,1,325,1,325,1,326,1,326,1,327,1,327,1,328,1,328, + 1,329,4,329,3412,8,329,11,329,12,329,3413,1,330,4,330,3417,8,330, + 11,330,12,330,3418,3,330,3421,8,330,1,330,1,330,4,330,3425,8,330, + 11,330,12,330,3426,1,331,1,331,4,331,3431,8,331,11,331,12,331,3432, + 4,331,3435,8,331,11,331,12,331,3436,1,332,1,332,5,332,3441,8,332, + 10,332,12,332,3444,9,332,1,333,4,333,3447,8,333,11,333,12,333,3448, + 1,333,5,333,3452,8,333,10,333,12,333,3455,9,333,1,333,1,333,1,334, + 3,334,3460,8,334,1,334,1,334,1,334,1,335,1,335,1,335,1,335,1,335, + 1,335,5,335,3471,8,335,10,335,12,335,3474,9,335,1,335,1,335,1,336, + 1,336,1,336,1,336,1,336,1,336,5,336,3484,8,336,10,336,12,336,3487, + 9,336,1,336,1,336,1,337,1,337,1,337,1,337,1,337,1,337,5,337,3497, + 8,337,10,337,12,337,3500,9,337,1,337,1,337,1,338,1,338,1,339,1,339, + 1,339,1,339,1,3448,0,340,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9, + 19,10,21,11,23,12,25,13,27,14,29,15,31,16,33,17,35,18,37,19,39,20, + 41,21,43,22,45,23,47,24,49,25,51,26,53,27,55,28,57,29,59,30,61,31, + 63,32,65,33,67,34,69,35,71,36,73,37,75,38,77,39,79,40,81,41,83,42, + 85,43,87,44,89,45,91,46,93,47,95,48,97,49,99,50,101,51,103,52,105, + 53,107,54,109,55,111,56,113,57,115,58,117,59,119,60,121,61,123,62, + 125,63,127,64,129,65,131,66,133,67,135,68,137,69,139,70,141,71,143, + 72,145,73,147,74,149,75,151,76,153,77,155,78,157,79,159,80,161,81, + 163,82,165,83,167,84,169,85,171,86,173,87,175,88,177,89,179,90,181, + 91,183,92,185,93,187,94,189,95,191,96,193,97,195,98,197,99,199,100, + 201,101,203,102,205,103,207,104,209,105,211,106,213,107,215,108, + 217,109,219,110,221,111,223,112,225,113,227,114,229,115,231,116, + 233,117,235,118,237,119,239,120,241,121,243,122,245,123,247,124, + 249,125,251,126,253,127,255,128,257,129,259,130,261,131,263,132, + 265,133,267,134,269,135,271,136,273,137,275,138,277,139,279,140, + 281,141,283,142,285,143,287,144,289,145,291,146,293,147,295,148, + 297,149,299,150,301,151,303,152,305,153,307,154,309,155,311,156, + 313,157,315,158,317,159,319,160,321,161,323,162,325,163,327,164, + 329,165,331,166,333,167,335,168,337,169,339,170,341,171,343,172, + 345,173,347,174,349,175,351,176,353,177,355,178,357,179,359,180, + 361,181,363,182,365,183,367,184,369,185,371,186,373,187,375,188, + 377,189,379,190,381,191,383,192,385,193,387,194,389,195,391,196, + 393,197,395,198,397,199,399,200,401,201,403,202,405,203,407,204, + 409,205,411,206,413,207,415,208,417,209,419,210,421,211,423,212, + 425,213,427,214,429,215,431,216,433,217,435,218,437,219,439,220, + 441,221,443,222,445,223,447,224,449,225,451,226,453,227,455,228, + 457,229,459,230,461,231,463,232,465,233,467,234,469,235,471,236, + 473,237,475,238,477,239,479,240,481,241,483,242,485,243,487,244, + 489,245,491,246,493,247,495,248,497,249,499,250,501,251,503,252, + 505,253,507,254,509,255,511,256,513,257,515,258,517,259,519,260, + 521,261,523,262,525,263,527,264,529,265,531,266,533,267,535,268, + 537,269,539,270,541,271,543,272,545,273,547,274,549,275,551,276, + 553,277,555,278,557,279,559,280,561,281,563,282,565,283,567,284, + 569,285,571,286,573,287,575,288,577,289,579,290,581,291,583,292, + 585,293,587,294,589,295,591,296,593,297,595,298,597,299,599,300, + 601,301,603,302,605,303,607,304,609,305,611,306,613,307,615,308, + 617,309,619,310,621,311,623,312,625,313,627,314,629,315,631,316, + 633,317,635,318,637,319,639,320,641,321,643,322,645,323,647,324, + 649,325,651,326,653,327,655,328,657,329,659,330,661,331,663,0,665, + 0,667,0,669,332,671,333,673,334,675,335,677,0,679,336,1,0,35,3,0, + 9,10,13,13,32,32,2,0,83,83,115,115,2,0,69,69,101,101,2,0,65,65,97, + 97,2,0,82,82,114,114,2,0,67,67,99,99,2,0,72,72,104,104,2,0,68,68, + 100,100,2,0,73,73,105,105,2,0,66,66,98,98,2,0,79,79,111,111,2,0, + 87,87,119,119,2,0,70,70,102,102,2,0,77,77,109,109,2,0,76,76,108, + 108,2,0,78,78,110,110,2,0,84,84,116,116,2,0,85,85,117,117,2,0,80, + 80,112,112,2,0,86,86,118,118,2,0,71,71,103,103,2,0,88,88,120,120, + 2,0,75,75,107,107,2,0,89,89,121,121,2,0,90,90,122,122,2,0,81,81, + 113,113,1,0,45,46,2,0,42,42,48,57,3,0,42,42,64,90,97,122,6,0,42, + 42,45,45,48,57,65,90,95,95,97,122,3,0,42,42,65,90,97,122,2,0,34, + 34,92,92,2,0,39,39,92,92,2,0,92,92,96,96,1,0,48,57,3524,0,1,1,0, + 0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0, + 0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0, + 0,23,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0, + 0,33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0, + 0,43,1,0,0,0,0,45,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0, + 0,53,1,0,0,0,0,55,1,0,0,0,0,57,1,0,0,0,0,59,1,0,0,0,0,61,1,0,0,0, + 0,63,1,0,0,0,0,65,1,0,0,0,0,67,1,0,0,0,0,69,1,0,0,0,0,71,1,0,0,0, + 0,73,1,0,0,0,0,75,1,0,0,0,0,77,1,0,0,0,0,79,1,0,0,0,0,81,1,0,0,0, + 0,83,1,0,0,0,0,85,1,0,0,0,0,87,1,0,0,0,0,89,1,0,0,0,0,91,1,0,0,0, + 0,93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0,0,0,101,1,0,0, + 0,0,103,1,0,0,0,0,105,1,0,0,0,0,107,1,0,0,0,0,109,1,0,0,0,0,111, + 1,0,0,0,0,113,1,0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,0,119,1,0,0,0, + 0,121,1,0,0,0,0,123,1,0,0,0,0,125,1,0,0,0,0,127,1,0,0,0,0,129,1, + 0,0,0,0,131,1,0,0,0,0,133,1,0,0,0,0,135,1,0,0,0,0,137,1,0,0,0,0, + 139,1,0,0,0,0,141,1,0,0,0,0,143,1,0,0,0,0,145,1,0,0,0,0,147,1,0, + 0,0,0,149,1,0,0,0,0,151,1,0,0,0,0,153,1,0,0,0,0,155,1,0,0,0,0,157, + 1,0,0,0,0,159,1,0,0,0,0,161,1,0,0,0,0,163,1,0,0,0,0,165,1,0,0,0, + 0,167,1,0,0,0,0,169,1,0,0,0,0,171,1,0,0,0,0,173,1,0,0,0,0,175,1, + 0,0,0,0,177,1,0,0,0,0,179,1,0,0,0,0,181,1,0,0,0,0,183,1,0,0,0,0, + 185,1,0,0,0,0,187,1,0,0,0,0,189,1,0,0,0,0,191,1,0,0,0,0,193,1,0, + 0,0,0,195,1,0,0,0,0,197,1,0,0,0,0,199,1,0,0,0,0,201,1,0,0,0,0,203, + 1,0,0,0,0,205,1,0,0,0,0,207,1,0,0,0,0,209,1,0,0,0,0,211,1,0,0,0, + 0,213,1,0,0,0,0,215,1,0,0,0,0,217,1,0,0,0,0,219,1,0,0,0,0,221,1, + 0,0,0,0,223,1,0,0,0,0,225,1,0,0,0,0,227,1,0,0,0,0,229,1,0,0,0,0, + 231,1,0,0,0,0,233,1,0,0,0,0,235,1,0,0,0,0,237,1,0,0,0,0,239,1,0, + 0,0,0,241,1,0,0,0,0,243,1,0,0,0,0,245,1,0,0,0,0,247,1,0,0,0,0,249, + 1,0,0,0,0,251,1,0,0,0,0,253,1,0,0,0,0,255,1,0,0,0,0,257,1,0,0,0, + 0,259,1,0,0,0,0,261,1,0,0,0,0,263,1,0,0,0,0,265,1,0,0,0,0,267,1, + 0,0,0,0,269,1,0,0,0,0,271,1,0,0,0,0,273,1,0,0,0,0,275,1,0,0,0,0, + 277,1,0,0,0,0,279,1,0,0,0,0,281,1,0,0,0,0,283,1,0,0,0,0,285,1,0, + 0,0,0,287,1,0,0,0,0,289,1,0,0,0,0,291,1,0,0,0,0,293,1,0,0,0,0,295, + 1,0,0,0,0,297,1,0,0,0,0,299,1,0,0,0,0,301,1,0,0,0,0,303,1,0,0,0, + 0,305,1,0,0,0,0,307,1,0,0,0,0,309,1,0,0,0,0,311,1,0,0,0,0,313,1, + 0,0,0,0,315,1,0,0,0,0,317,1,0,0,0,0,319,1,0,0,0,0,321,1,0,0,0,0, + 323,1,0,0,0,0,325,1,0,0,0,0,327,1,0,0,0,0,329,1,0,0,0,0,331,1,0, + 0,0,0,333,1,0,0,0,0,335,1,0,0,0,0,337,1,0,0,0,0,339,1,0,0,0,0,341, + 1,0,0,0,0,343,1,0,0,0,0,345,1,0,0,0,0,347,1,0,0,0,0,349,1,0,0,0, + 0,351,1,0,0,0,0,353,1,0,0,0,0,355,1,0,0,0,0,357,1,0,0,0,0,359,1, + 0,0,0,0,361,1,0,0,0,0,363,1,0,0,0,0,365,1,0,0,0,0,367,1,0,0,0,0, + 369,1,0,0,0,0,371,1,0,0,0,0,373,1,0,0,0,0,375,1,0,0,0,0,377,1,0, + 0,0,0,379,1,0,0,0,0,381,1,0,0,0,0,383,1,0,0,0,0,385,1,0,0,0,0,387, + 1,0,0,0,0,389,1,0,0,0,0,391,1,0,0,0,0,393,1,0,0,0,0,395,1,0,0,0, + 0,397,1,0,0,0,0,399,1,0,0,0,0,401,1,0,0,0,0,403,1,0,0,0,0,405,1, + 0,0,0,0,407,1,0,0,0,0,409,1,0,0,0,0,411,1,0,0,0,0,413,1,0,0,0,0, + 415,1,0,0,0,0,417,1,0,0,0,0,419,1,0,0,0,0,421,1,0,0,0,0,423,1,0, + 0,0,0,425,1,0,0,0,0,427,1,0,0,0,0,429,1,0,0,0,0,431,1,0,0,0,0,433, + 1,0,0,0,0,435,1,0,0,0,0,437,1,0,0,0,0,439,1,0,0,0,0,441,1,0,0,0, + 0,443,1,0,0,0,0,445,1,0,0,0,0,447,1,0,0,0,0,449,1,0,0,0,0,451,1, + 0,0,0,0,453,1,0,0,0,0,455,1,0,0,0,0,457,1,0,0,0,0,459,1,0,0,0,0, + 461,1,0,0,0,0,463,1,0,0,0,0,465,1,0,0,0,0,467,1,0,0,0,0,469,1,0, + 0,0,0,471,1,0,0,0,0,473,1,0,0,0,0,475,1,0,0,0,0,477,1,0,0,0,0,479, + 1,0,0,0,0,481,1,0,0,0,0,483,1,0,0,0,0,485,1,0,0,0,0,487,1,0,0,0, + 0,489,1,0,0,0,0,491,1,0,0,0,0,493,1,0,0,0,0,495,1,0,0,0,0,497,1, + 0,0,0,0,499,1,0,0,0,0,501,1,0,0,0,0,503,1,0,0,0,0,505,1,0,0,0,0, + 507,1,0,0,0,0,509,1,0,0,0,0,511,1,0,0,0,0,513,1,0,0,0,0,515,1,0, + 0,0,0,517,1,0,0,0,0,519,1,0,0,0,0,521,1,0,0,0,0,523,1,0,0,0,0,525, + 1,0,0,0,0,527,1,0,0,0,0,529,1,0,0,0,0,531,1,0,0,0,0,533,1,0,0,0, + 0,535,1,0,0,0,0,537,1,0,0,0,0,539,1,0,0,0,0,541,1,0,0,0,0,543,1, + 0,0,0,0,545,1,0,0,0,0,547,1,0,0,0,0,549,1,0,0,0,0,551,1,0,0,0,0, + 553,1,0,0,0,0,555,1,0,0,0,0,557,1,0,0,0,0,559,1,0,0,0,0,561,1,0, + 0,0,0,563,1,0,0,0,0,565,1,0,0,0,0,567,1,0,0,0,0,569,1,0,0,0,0,571, + 1,0,0,0,0,573,1,0,0,0,0,575,1,0,0,0,0,577,1,0,0,0,0,579,1,0,0,0, + 0,581,1,0,0,0,0,583,1,0,0,0,0,585,1,0,0,0,0,587,1,0,0,0,0,589,1, + 0,0,0,0,591,1,0,0,0,0,593,1,0,0,0,0,595,1,0,0,0,0,597,1,0,0,0,0, + 599,1,0,0,0,0,601,1,0,0,0,0,603,1,0,0,0,0,605,1,0,0,0,0,607,1,0, + 0,0,0,609,1,0,0,0,0,611,1,0,0,0,0,613,1,0,0,0,0,615,1,0,0,0,0,617, + 1,0,0,0,0,619,1,0,0,0,0,621,1,0,0,0,0,623,1,0,0,0,0,625,1,0,0,0, + 0,627,1,0,0,0,0,629,1,0,0,0,0,631,1,0,0,0,0,633,1,0,0,0,0,635,1, + 0,0,0,0,637,1,0,0,0,0,639,1,0,0,0,0,641,1,0,0,0,0,643,1,0,0,0,0, + 645,1,0,0,0,0,647,1,0,0,0,0,649,1,0,0,0,0,651,1,0,0,0,0,653,1,0, + 0,0,0,655,1,0,0,0,0,657,1,0,0,0,0,659,1,0,0,0,0,661,1,0,0,0,0,669, + 1,0,0,0,0,671,1,0,0,0,0,673,1,0,0,0,0,675,1,0,0,0,0,679,1,0,0,0, + 1,682,1,0,0,0,3,688,1,0,0,0,5,695,1,0,0,0,7,704,1,0,0,0,9,709,1, + 0,0,0,11,714,1,0,0,0,13,720,1,0,0,0,15,727,1,0,0,0,17,734,1,0,0, + 0,19,740,1,0,0,0,21,746,1,0,0,0,23,751,1,0,0,0,25,756,1,0,0,0,27, + 761,1,0,0,0,29,765,1,0,0,0,31,770,1,0,0,0,33,776,1,0,0,0,35,783, + 1,0,0,0,37,789,1,0,0,0,39,795,1,0,0,0,41,800,1,0,0,0,43,808,1,0, + 0,0,45,817,1,0,0,0,47,827,1,0,0,0,49,834,1,0,0,0,51,837,1,0,0,0, + 53,840,1,0,0,0,55,843,1,0,0,0,57,846,1,0,0,0,59,853,1,0,0,0,61,859, + 1,0,0,0,63,861,1,0,0,0,65,866,1,0,0,0,67,878,1,0,0,0,69,885,1,0, + 0,0,71,890,1,0,0,0,73,894,1,0,0,0,75,897,1,0,0,0,77,901,1,0,0,0, + 79,911,1,0,0,0,81,923,1,0,0,0,83,941,1,0,0,0,85,952,1,0,0,0,87,959, + 1,0,0,0,89,965,1,0,0,0,91,975,1,0,0,0,93,986,1,0,0,0,95,1000,1,0, + 0,0,97,1016,1,0,0,0,99,1029,1,0,0,0,101,1041,1,0,0,0,103,1054,1, + 0,0,0,105,1065,1,0,0,0,107,1078,1,0,0,0,109,1093,1,0,0,0,111,1104, + 1,0,0,0,113,1114,1,0,0,0,115,1133,1,0,0,0,117,1157,1,0,0,0,119,1162, + 1,0,0,0,121,1165,1,0,0,0,123,1169,1,0,0,0,125,1172,1,0,0,0,127,1176, + 1,0,0,0,129,1180,1,0,0,0,131,1185,1,0,0,0,133,1191,1,0,0,0,135,1198, + 1,0,0,0,137,1209,1,0,0,0,139,1218,1,0,0,0,141,1222,1,0,0,0,143,1231, + 1,0,0,0,145,1247,1,0,0,0,147,1258,1,0,0,0,149,1270,1,0,0,0,151,1281, + 1,0,0,0,153,1286,1,0,0,0,155,1303,1,0,0,0,157,1315,1,0,0,0,159,1327, + 1,0,0,0,161,1339,1,0,0,0,163,1348,1,0,0,0,165,1360,1,0,0,0,167,1372, + 1,0,0,0,169,1379,1,0,0,0,171,1398,1,0,0,0,173,1412,1,0,0,0,175,1427, + 1,0,0,0,177,1441,1,0,0,0,179,1447,1,0,0,0,181,1461,1,0,0,0,183,1469, + 1,0,0,0,185,1476,1,0,0,0,187,1495,1,0,0,0,189,1512,1,0,0,0,191,1517, + 1,0,0,0,193,1530,1,0,0,0,195,1535,1,0,0,0,197,1546,1,0,0,0,199,1556, + 1,0,0,0,201,1563,1,0,0,0,203,1575,1,0,0,0,205,1579,1,0,0,0,207,1587, + 1,0,0,0,209,1594,1,0,0,0,211,1599,1,0,0,0,213,1605,1,0,0,0,215,1612, + 1,0,0,0,217,1620,1,0,0,0,219,1622,1,0,0,0,221,1624,1,0,0,0,223,1626, + 1,0,0,0,225,1628,1,0,0,0,227,1630,1,0,0,0,229,1632,1,0,0,0,231,1635, + 1,0,0,0,233,1638,1,0,0,0,235,1641,1,0,0,0,237,1643,1,0,0,0,239,1645, + 1,0,0,0,241,1647,1,0,0,0,243,1649,1,0,0,0,245,1651,1,0,0,0,247,1653, + 1,0,0,0,249,1655,1,0,0,0,251,1657,1,0,0,0,253,1659,1,0,0,0,255,1661, + 1,0,0,0,257,1663,1,0,0,0,259,1665,1,0,0,0,261,1667,1,0,0,0,263,1669, + 1,0,0,0,265,1671,1,0,0,0,267,1673,1,0,0,0,269,1675,1,0,0,0,271,1679, + 1,0,0,0,273,1685,1,0,0,0,275,1700,1,0,0,0,277,1706,1,0,0,0,279,1718, + 1,0,0,0,281,1722,1,0,0,0,283,1727,1,0,0,0,285,1734,1,0,0,0,287,1738, + 1,0,0,0,289,1743,1,0,0,0,291,1749,1,0,0,0,293,1755,1,0,0,0,295,1762, + 1,0,0,0,297,1766,1,0,0,0,299,1772,1,0,0,0,301,1781,1,0,0,0,303,1789, + 1,0,0,0,305,1801,1,0,0,0,307,1812,1,0,0,0,309,1823,1,0,0,0,311,1828, + 1,0,0,0,313,1834,1,0,0,0,315,1839,1,0,0,0,317,1844,1,0,0,0,319,1851, + 1,0,0,0,321,1860,1,0,0,0,323,1874,1,0,0,0,325,1881,1,0,0,0,327,1893, + 1,0,0,0,329,1901,1,0,0,0,331,1910,1,0,0,0,333,1921,1,0,0,0,335,1932, + 1,0,0,0,337,1937,1,0,0,0,339,1947,1,0,0,0,341,1949,1,0,0,0,343,1952, + 1,0,0,0,345,1956,1,0,0,0,347,1961,1,0,0,0,349,1966,1,0,0,0,351,1974, + 1,0,0,0,353,1979,1,0,0,0,355,1985,1,0,0,0,357,1987,1,0,0,0,359,1991, + 1,0,0,0,361,1997,1,0,0,0,363,2000,1,0,0,0,365,2004,1,0,0,0,367,2010, + 1,0,0,0,369,2015,1,0,0,0,371,2019,1,0,0,0,373,2022,1,0,0,0,375,2031, + 1,0,0,0,377,2035,1,0,0,0,379,2041,1,0,0,0,381,2046,1,0,0,0,383,2052, + 1,0,0,0,385,2057,1,0,0,0,387,2062,1,0,0,0,389,2071,1,0,0,0,391,2076, + 1,0,0,0,393,2081,1,0,0,0,395,2086,1,0,0,0,397,2092,1,0,0,0,399,2096, + 1,0,0,0,401,2100,1,0,0,0,403,2108,1,0,0,0,405,2116,1,0,0,0,407,2120, + 1,0,0,0,409,2124,1,0,0,0,411,2132,1,0,0,0,413,2140,1,0,0,0,415,2148, + 1,0,0,0,417,2161,1,0,0,0,419,2174,1,0,0,0,421,2192,1,0,0,0,423,2200, + 1,0,0,0,425,2205,1,0,0,0,427,2214,1,0,0,0,429,2223,1,0,0,0,431,2235, + 1,0,0,0,433,2244,1,0,0,0,435,2252,1,0,0,0,437,2263,1,0,0,0,439,2273, + 1,0,0,0,441,2283,1,0,0,0,443,2296,1,0,0,0,445,2308,1,0,0,0,447,2316, + 1,0,0,0,449,2326,1,0,0,0,451,2340,1,0,0,0,453,2351,1,0,0,0,455,2360, + 1,0,0,0,457,2370,1,0,0,0,459,2385,1,0,0,0,461,2394,1,0,0,0,463,2403, + 1,0,0,0,465,2413,1,0,0,0,467,2417,1,0,0,0,469,2428,1,0,0,0,471,2440, + 1,0,0,0,473,2452,1,0,0,0,475,2464,1,0,0,0,477,2472,1,0,0,0,479,2480, + 1,0,0,0,481,2488,1,0,0,0,483,2493,1,0,0,0,485,2502,1,0,0,0,487,2512, + 1,0,0,0,489,2525,1,0,0,0,491,2539,1,0,0,0,493,2551,1,0,0,0,495,2563, + 1,0,0,0,497,2571,1,0,0,0,499,2582,1,0,0,0,501,2597,1,0,0,0,503,2606, + 1,0,0,0,505,2615,1,0,0,0,507,2629,1,0,0,0,509,2637,1,0,0,0,511,2646, + 1,0,0,0,513,2653,1,0,0,0,515,2663,1,0,0,0,517,2669,1,0,0,0,519,2675, + 1,0,0,0,521,2680,1,0,0,0,523,2683,1,0,0,0,525,2689,1,0,0,0,527,2695, + 1,0,0,0,529,2702,1,0,0,0,531,2712,1,0,0,0,533,2719,1,0,0,0,535,2726, + 1,0,0,0,537,2732,1,0,0,0,539,2737,1,0,0,0,541,2743,1,0,0,0,543,2750, + 1,0,0,0,545,2758,1,0,0,0,547,2766,1,0,0,0,549,2771,1,0,0,0,551,2776, + 1,0,0,0,553,2783,1,0,0,0,555,2793,1,0,0,0,557,2800,1,0,0,0,559,2807, + 1,0,0,0,561,2810,1,0,0,0,563,2817,1,0,0,0,565,2823,1,0,0,0,567,2836, + 1,0,0,0,569,2856,1,0,0,0,571,2874,1,0,0,0,573,2894,1,0,0,0,575,2906, + 1,0,0,0,577,2919,1,0,0,0,579,2942,1,0,0,0,581,2959,1,0,0,0,583,2968, + 1,0,0,0,585,3004,1,0,0,0,587,3010,1,0,0,0,589,3027,1,0,0,0,591,3041, + 1,0,0,0,593,3058,1,0,0,0,595,3085,1,0,0,0,597,3092,1,0,0,0,599,3098, + 1,0,0,0,601,3119,1,0,0,0,603,3139,1,0,0,0,605,3160,1,0,0,0,607,3174, + 1,0,0,0,609,3184,1,0,0,0,611,3192,1,0,0,0,613,3210,1,0,0,0,615,3234, + 1,0,0,0,617,3249,1,0,0,0,619,3270,1,0,0,0,621,3279,1,0,0,0,623,3291, + 1,0,0,0,625,3305,1,0,0,0,627,3320,1,0,0,0,629,3339,1,0,0,0,631,3347, + 1,0,0,0,633,3352,1,0,0,0,635,3364,1,0,0,0,637,3369,1,0,0,0,639,3386, + 1,0,0,0,641,3391,1,0,0,0,643,3394,1,0,0,0,645,3396,1,0,0,0,647,3398, + 1,0,0,0,649,3400,1,0,0,0,651,3402,1,0,0,0,653,3404,1,0,0,0,655,3406, + 1,0,0,0,657,3408,1,0,0,0,659,3411,1,0,0,0,661,3420,1,0,0,0,663,3434, + 1,0,0,0,665,3438,1,0,0,0,667,3446,1,0,0,0,669,3459,1,0,0,0,671,3464, + 1,0,0,0,673,3477,1,0,0,0,675,3490,1,0,0,0,677,3503,1,0,0,0,679,3505, + 1,0,0,0,681,683,7,0,0,0,682,681,1,0,0,0,683,684,1,0,0,0,684,682, + 1,0,0,0,684,685,1,0,0,0,685,686,1,0,0,0,686,687,6,0,0,0,687,2,1, + 0,0,0,688,689,7,1,0,0,689,690,7,2,0,0,690,691,7,3,0,0,691,692,7, + 4,0,0,692,693,7,5,0,0,693,694,7,6,0,0,694,4,1,0,0,0,695,696,7,7, + 0,0,696,697,7,2,0,0,697,698,7,1,0,0,698,699,7,5,0,0,699,700,7,4, + 0,0,700,701,7,8,0,0,701,702,7,9,0,0,702,703,7,2,0,0,703,6,1,0,0, + 0,704,705,7,1,0,0,705,706,7,6,0,0,706,707,7,10,0,0,707,708,7,11, + 0,0,708,8,1,0,0,0,709,710,7,12,0,0,710,711,7,4,0,0,711,712,7,10, + 0,0,712,713,7,13,0,0,713,10,1,0,0,0,714,715,7,11,0,0,715,716,7,6, + 0,0,716,717,7,2,0,0,717,718,7,4,0,0,718,719,7,2,0,0,719,12,1,0,0, + 0,720,721,7,12,0,0,721,722,7,8,0,0,722,723,7,2,0,0,723,724,7,14, + 0,0,724,725,7,7,0,0,725,726,7,1,0,0,726,14,1,0,0,0,727,728,7,4,0, + 0,728,729,7,2,0,0,729,730,7,15,0,0,730,731,7,3,0,0,731,732,7,13, + 0,0,732,733,7,2,0,0,733,16,1,0,0,0,734,735,7,1,0,0,735,736,7,16, + 0,0,736,737,7,3,0,0,737,738,7,16,0,0,738,739,7,1,0,0,739,18,1,0, + 0,0,740,741,7,7,0,0,741,742,7,2,0,0,742,743,7,7,0,0,743,744,7,17, + 0,0,744,745,7,18,0,0,745,20,1,0,0,0,746,747,7,1,0,0,747,748,7,10, + 0,0,748,749,7,4,0,0,749,750,7,16,0,0,750,22,1,0,0,0,751,752,7,2, + 0,0,752,753,7,19,0,0,753,754,7,3,0,0,754,755,7,14,0,0,755,24,1,0, + 0,0,756,757,7,6,0,0,757,758,7,2,0,0,758,759,7,3,0,0,759,760,7,7, + 0,0,760,26,1,0,0,0,761,762,7,16,0,0,762,763,7,10,0,0,763,764,7,18, + 0,0,764,28,1,0,0,0,765,766,7,4,0,0,766,767,7,3,0,0,767,768,7,4,0, + 0,768,769,7,2,0,0,769,30,1,0,0,0,770,771,7,18,0,0,771,772,7,3,0, + 0,772,773,7,4,0,0,773,774,7,1,0,0,774,775,7,2,0,0,775,32,1,0,0,0, + 776,777,7,13,0,0,777,778,7,2,0,0,778,779,7,16,0,0,779,780,7,6,0, + 0,780,781,7,10,0,0,781,782,7,7,0,0,782,34,1,0,0,0,783,784,7,4,0, + 0,784,785,7,2,0,0,785,786,7,20,0,0,786,787,7,2,0,0,787,788,7,21, + 0,0,788,36,1,0,0,0,789,790,7,18,0,0,790,791,7,17,0,0,791,792,7,15, + 0,0,792,793,7,5,0,0,793,794,7,16,0,0,794,38,1,0,0,0,795,796,7,20, + 0,0,796,797,7,4,0,0,797,798,7,10,0,0,798,799,7,22,0,0,799,40,1,0, + 0,0,800,801,7,18,0,0,801,802,7,3,0,0,802,803,7,16,0,0,803,804,7, + 16,0,0,804,805,7,2,0,0,805,806,7,4,0,0,806,807,7,15,0,0,807,42,1, + 0,0,0,808,809,7,18,0,0,809,810,7,3,0,0,810,811,7,16,0,0,811,812, + 7,16,0,0,812,813,7,2,0,0,813,814,7,4,0,0,814,815,7,15,0,0,815,816, + 7,1,0,0,816,44,1,0,0,0,817,818,7,15,0,0,818,819,7,2,0,0,819,820, + 7,11,0,0,820,821,5,95,0,0,821,822,7,12,0,0,822,823,7,8,0,0,823,824, + 7,2,0,0,824,825,7,14,0,0,825,826,7,7,0,0,826,46,1,0,0,0,827,828, + 7,22,0,0,828,829,7,13,0,0,829,830,7,2,0,0,830,831,7,3,0,0,831,832, + 7,15,0,0,832,833,7,1,0,0,833,48,1,0,0,0,834,835,7,3,0,0,835,836, + 7,7,0,0,836,50,1,0,0,0,837,838,7,13,0,0,838,839,7,14,0,0,839,52, + 1,0,0,0,840,841,7,3,0,0,841,842,7,1,0,0,842,54,1,0,0,0,843,844,7, + 9,0,0,844,845,7,23,0,0,845,56,1,0,0,0,846,847,7,1,0,0,847,848,7, + 10,0,0,848,849,7,17,0,0,849,850,7,4,0,0,850,851,7,5,0,0,851,852, + 7,2,0,0,852,58,1,0,0,0,853,854,7,8,0,0,854,855,7,15,0,0,855,856, + 7,7,0,0,856,857,7,2,0,0,857,858,7,21,0,0,858,60,1,0,0,0,859,860, + 7,7,0,0,860,62,1,0,0,0,861,862,7,7,0,0,862,863,7,2,0,0,863,864,7, + 1,0,0,864,865,7,5,0,0,865,64,1,0,0,0,866,867,7,7,0,0,867,868,7,3, + 0,0,868,869,7,16,0,0,869,870,7,3,0,0,870,871,7,1,0,0,871,872,7,10, + 0,0,872,873,7,17,0,0,873,874,7,4,0,0,874,875,7,5,0,0,875,876,7,2, + 0,0,876,877,7,1,0,0,877,66,1,0,0,0,878,879,7,1,0,0,879,880,7,10, + 0,0,880,881,7,4,0,0,881,882,7,16,0,0,882,883,7,9,0,0,883,884,7,23, + 0,0,884,68,1,0,0,0,885,886,7,3,0,0,886,887,7,17,0,0,887,888,7,16, + 0,0,888,889,7,10,0,0,889,70,1,0,0,0,890,891,7,1,0,0,891,892,7,16, + 0,0,892,893,7,4,0,0,893,72,1,0,0,0,894,895,7,8,0,0,895,896,7,18, + 0,0,896,74,1,0,0,0,897,898,7,15,0,0,898,899,7,17,0,0,899,900,7,13, + 0,0,900,76,1,0,0,0,901,902,7,22,0,0,902,903,7,2,0,0,903,904,7,2, + 0,0,904,905,7,18,0,0,905,906,7,2,0,0,906,907,7,13,0,0,907,908,7, + 18,0,0,908,909,7,16,0,0,909,910,7,23,0,0,910,78,1,0,0,0,911,912, + 7,5,0,0,912,913,7,10,0,0,913,914,7,15,0,0,914,915,7,1,0,0,915,916, + 7,2,0,0,916,917,7,5,0,0,917,918,7,17,0,0,918,919,7,16,0,0,919,920, + 7,8,0,0,920,921,7,19,0,0,921,922,7,2,0,0,922,80,1,0,0,0,923,924, + 7,7,0,0,924,925,7,2,0,0,925,926,7,7,0,0,926,927,7,17,0,0,927,928, + 7,18,0,0,928,929,5,95,0,0,929,930,7,1,0,0,930,931,7,18,0,0,931,932, + 7,14,0,0,932,933,7,8,0,0,933,934,7,16,0,0,934,935,7,19,0,0,935,936, + 7,3,0,0,936,937,7,14,0,0,937,938,7,17,0,0,938,939,7,2,0,0,939,940, + 7,1,0,0,940,82,1,0,0,0,941,942,7,18,0,0,942,943,7,3,0,0,943,944, + 7,4,0,0,944,945,7,16,0,0,945,946,7,8,0,0,946,947,7,16,0,0,947,948, + 7,8,0,0,948,949,7,10,0,0,949,950,7,15,0,0,950,951,7,1,0,0,951,84, + 1,0,0,0,952,953,7,3,0,0,953,954,7,14,0,0,954,955,7,14,0,0,955,956, + 7,15,0,0,956,957,7,17,0,0,957,958,7,13,0,0,958,86,1,0,0,0,959,960, + 7,7,0,0,960,961,7,2,0,0,961,962,7,14,0,0,962,963,7,8,0,0,963,964, + 7,13,0,0,964,88,1,0,0,0,965,966,7,5,0,0,966,967,7,2,0,0,967,968, + 7,15,0,0,968,969,7,16,0,0,969,970,7,4,0,0,970,971,7,10,0,0,971,972, + 7,8,0,0,972,973,7,7,0,0,973,974,7,1,0,0,974,90,1,0,0,0,975,976,7, + 8,0,0,976,977,7,16,0,0,977,978,7,2,0,0,978,979,7,4,0,0,979,980,7, + 3,0,0,980,981,7,16,0,0,981,982,7,8,0,0,982,983,7,10,0,0,983,984, + 7,15,0,0,984,985,7,1,0,0,985,92,1,0,0,0,986,987,7,7,0,0,987,988, + 7,8,0,0,988,989,7,1,0,0,989,990,7,16,0,0,990,991,7,3,0,0,991,992, + 7,15,0,0,992,993,7,5,0,0,993,994,7,2,0,0,994,995,5,95,0,0,995,996, + 7,16,0,0,996,997,7,23,0,0,997,998,7,18,0,0,998,999,7,2,0,0,999,94, + 1,0,0,0,1000,1001,7,15,0,0,1001,1002,7,17,0,0,1002,1003,7,13,0,0, + 1003,1004,7,9,0,0,1004,1005,7,2,0,0,1005,1006,7,4,0,0,1006,1007, + 5,95,0,0,1007,1008,7,10,0,0,1008,1009,7,12,0,0,1009,1010,5,95,0, + 0,1010,1011,7,16,0,0,1011,1012,7,4,0,0,1012,1013,7,2,0,0,1013,1014, + 7,2,0,0,1014,1015,7,1,0,0,1015,96,1,0,0,0,1016,1017,7,1,0,0,1017, + 1018,7,6,0,0,1018,1019,7,8,0,0,1019,1020,7,15,0,0,1020,1021,7,20, + 0,0,1021,1022,7,14,0,0,1022,1023,7,2,0,0,1023,1024,5,95,0,0,1024, + 1025,7,1,0,0,1025,1026,7,8,0,0,1026,1027,7,24,0,0,1027,1028,7,2, + 0,0,1028,98,1,0,0,0,1029,1030,7,1,0,0,1030,1031,7,3,0,0,1031,1032, + 7,13,0,0,1032,1033,7,18,0,0,1033,1034,7,14,0,0,1034,1035,7,2,0,0, + 1035,1036,5,95,0,0,1036,1037,7,1,0,0,1037,1038,7,8,0,0,1038,1039, + 7,24,0,0,1039,1040,7,2,0,0,1040,100,1,0,0,0,1041,1042,7,10,0,0,1042, + 1043,7,17,0,0,1043,1044,7,16,0,0,1044,1045,7,18,0,0,1045,1046,7, + 17,0,0,1046,1047,7,16,0,0,1047,1048,5,95,0,0,1048,1049,7,3,0,0,1049, + 1050,7,12,0,0,1050,1051,7,16,0,0,1051,1052,7,2,0,0,1052,1053,7,4, + 0,0,1053,102,1,0,0,0,1054,1055,7,16,0,0,1055,1056,7,8,0,0,1056,1057, + 7,13,0,0,1057,1058,7,2,0,0,1058,1059,5,95,0,0,1059,1060,7,7,0,0, + 1060,1061,7,2,0,0,1061,1062,7,5,0,0,1062,1063,7,3,0,0,1063,1064, + 7,23,0,0,1064,104,1,0,0,0,1065,1066,7,3,0,0,1066,1067,7,15,0,0,1067, + 1068,7,10,0,0,1068,1069,7,13,0,0,1069,1070,7,3,0,0,1070,1071,7,14, + 0,0,1071,1072,7,23,0,0,1072,1073,5,95,0,0,1073,1074,7,4,0,0,1074, + 1075,7,3,0,0,1075,1076,7,16,0,0,1076,1077,7,2,0,0,1077,106,1,0,0, + 0,1078,1079,7,5,0,0,1079,1080,7,3,0,0,1080,1081,7,16,0,0,1081,1082, + 7,2,0,0,1082,1083,7,20,0,0,1083,1084,7,10,0,0,1084,1085,7,4,0,0, + 1085,1086,7,23,0,0,1086,1087,5,95,0,0,1087,1088,7,12,0,0,1088,1089, + 7,8,0,0,1089,1090,7,2,0,0,1090,1091,7,14,0,0,1091,1092,7,7,0,0,1092, + 108,1,0,0,0,1093,1094,7,16,0,0,1094,1095,7,8,0,0,1095,1096,7,13, + 0,0,1096,1097,7,2,0,0,1097,1098,5,95,0,0,1098,1099,7,12,0,0,1099, + 1100,7,8,0,0,1100,1101,7,2,0,0,1101,1102,7,14,0,0,1102,1103,7,7, + 0,0,1103,110,1,0,0,0,1104,1105,7,16,0,0,1105,1106,7,8,0,0,1106,1107, + 7,13,0,0,1107,1108,7,2,0,0,1108,1109,5,95,0,0,1109,1110,7,24,0,0, + 1110,1111,7,10,0,0,1111,1112,7,15,0,0,1112,1113,7,2,0,0,1113,112, + 1,0,0,0,1114,1115,7,16,0,0,1115,1116,7,4,0,0,1116,1117,7,3,0,0,1117, + 1118,7,8,0,0,1118,1119,7,15,0,0,1119,1120,7,8,0,0,1120,1121,7,15, + 0,0,1121,1122,7,20,0,0,1122,1123,5,95,0,0,1123,1124,7,7,0,0,1124, + 1125,7,3,0,0,1125,1126,7,16,0,0,1126,1127,7,3,0,0,1127,1128,5,95, + 0,0,1128,1129,7,1,0,0,1129,1130,7,8,0,0,1130,1131,7,24,0,0,1131, + 1132,7,2,0,0,1132,114,1,0,0,0,1133,1134,7,3,0,0,1134,1135,7,15,0, + 0,1135,1136,7,10,0,0,1136,1137,7,13,0,0,1137,1138,7,3,0,0,1138,1139, + 7,14,0,0,1139,1140,7,23,0,0,1140,1141,5,95,0,0,1141,1142,7,1,0,0, + 1142,1143,7,5,0,0,1143,1144,7,10,0,0,1144,1145,7,4,0,0,1145,1146, + 7,2,0,0,1146,1147,5,95,0,0,1147,1148,7,16,0,0,1148,1149,7,6,0,0, + 1149,1150,7,4,0,0,1150,1151,7,2,0,0,1151,1152,7,1,0,0,1152,1153, + 7,6,0,0,1153,1154,7,10,0,0,1154,1155,7,14,0,0,1155,1156,7,7,0,0, + 1156,116,1,0,0,0,1157,1158,7,5,0,0,1158,1159,7,3,0,0,1159,1160,7, + 1,0,0,1160,1161,7,2,0,0,1161,118,1,0,0,0,1162,1163,7,8,0,0,1163, + 1164,7,15,0,0,1164,120,1,0,0,0,1165,1166,7,15,0,0,1166,1167,7,10, + 0,0,1167,1168,7,16,0,0,1168,122,1,0,0,0,1169,1170,7,10,0,0,1170, + 1171,7,4,0,0,1171,124,1,0,0,0,1172,1173,7,3,0,0,1173,1174,7,15,0, + 0,1174,1175,7,7,0,0,1175,126,1,0,0,0,1176,1177,7,21,0,0,1177,1178, + 7,10,0,0,1178,1179,7,4,0,0,1179,128,1,0,0,0,1180,1181,7,16,0,0,1181, + 1182,7,4,0,0,1182,1183,7,17,0,0,1183,1184,7,2,0,0,1184,130,1,0,0, + 0,1185,1186,7,12,0,0,1186,1187,7,3,0,0,1187,1188,7,14,0,0,1188,1189, + 7,1,0,0,1189,1190,7,2,0,0,1190,132,1,0,0,0,1191,1192,7,4,0,0,1192, + 1193,7,2,0,0,1193,1194,7,20,0,0,1194,1195,7,2,0,0,1195,1196,7,21, + 0,0,1196,1197,7,18,0,0,1197,134,1,0,0,0,1198,1199,7,5,0,0,1199,1200, + 7,10,0,0,1200,1201,7,15,0,0,1201,1202,7,19,0,0,1202,1203,7,2,0,0, + 1203,1204,7,4,0,0,1204,1205,7,16,0,0,1205,1206,5,95,0,0,1206,1207, + 7,16,0,0,1207,1208,7,24,0,0,1208,136,1,0,0,0,1209,1210,7,7,0,0,1210, + 1211,7,3,0,0,1211,1212,7,16,0,0,1212,1213,7,2,0,0,1213,1214,7,16, + 0,0,1214,1215,7,8,0,0,1215,1216,7,13,0,0,1216,1217,7,2,0,0,1217, + 138,1,0,0,0,1218,1219,7,7,0,0,1219,1220,7,3,0,0,1220,1221,7,23,0, + 0,1221,140,1,0,0,0,1222,1223,7,7,0,0,1223,1224,7,3,0,0,1224,1225, + 7,23,0,0,1225,1226,5,95,0,0,1226,1227,7,6,0,0,1227,1228,7,10,0,0, + 1228,1229,7,17,0,0,1229,1230,7,4,0,0,1230,142,1,0,0,0,1231,1232, + 7,7,0,0,1232,1233,7,3,0,0,1233,1234,7,23,0,0,1234,1235,5,95,0,0, + 1235,1236,7,13,0,0,1236,1237,7,8,0,0,1237,1238,7,5,0,0,1238,1239, + 7,4,0,0,1239,1240,7,10,0,0,1240,1241,7,1,0,0,1241,1242,7,2,0,0,1242, + 1243,7,5,0,0,1243,1244,7,10,0,0,1244,1245,7,15,0,0,1245,1246,7,7, + 0,0,1246,144,1,0,0,0,1247,1248,7,7,0,0,1248,1249,7,3,0,0,1249,1250, + 7,23,0,0,1250,1251,5,95,0,0,1251,1252,7,13,0,0,1252,1253,7,8,0,0, + 1253,1254,7,15,0,0,1254,1255,7,17,0,0,1255,1256,7,16,0,0,1256,1257, + 7,2,0,0,1257,146,1,0,0,0,1258,1259,7,7,0,0,1259,1260,7,3,0,0,1260, + 1261,7,23,0,0,1261,1262,5,95,0,0,1262,1263,7,10,0,0,1263,1264,7, + 12,0,0,1264,1265,5,95,0,0,1265,1266,7,23,0,0,1266,1267,7,2,0,0,1267, + 1268,7,3,0,0,1268,1269,7,4,0,0,1269,148,1,0,0,0,1270,1271,7,7,0, + 0,1271,1272,7,3,0,0,1272,1273,7,23,0,0,1273,1274,5,95,0,0,1274,1275, + 7,1,0,0,1275,1276,7,2,0,0,1276,1277,7,5,0,0,1277,1278,7,10,0,0,1278, + 1279,7,15,0,0,1279,1280,7,7,0,0,1280,150,1,0,0,0,1281,1282,7,6,0, + 0,1282,1283,7,10,0,0,1283,1284,7,17,0,0,1284,1285,7,4,0,0,1285,152, + 1,0,0,0,1286,1287,7,6,0,0,1287,1288,7,10,0,0,1288,1289,7,17,0,0, + 1289,1290,7,4,0,0,1290,1291,5,95,0,0,1291,1292,7,13,0,0,1292,1293, + 7,8,0,0,1293,1294,7,5,0,0,1294,1295,7,4,0,0,1295,1296,7,10,0,0,1296, + 1297,7,1,0,0,1297,1298,7,2,0,0,1298,1299,7,5,0,0,1299,1300,7,10, + 0,0,1300,1301,7,15,0,0,1301,1302,7,7,0,0,1302,154,1,0,0,0,1303,1304, + 7,6,0,0,1304,1305,7,10,0,0,1305,1306,7,17,0,0,1306,1307,7,4,0,0, + 1307,1308,5,95,0,0,1308,1309,7,13,0,0,1309,1310,7,8,0,0,1310,1311, + 7,15,0,0,1311,1312,7,17,0,0,1312,1313,7,16,0,0,1313,1314,7,2,0,0, + 1314,156,1,0,0,0,1315,1316,7,6,0,0,1316,1317,7,10,0,0,1317,1318, + 7,17,0,0,1318,1319,7,4,0,0,1319,1320,5,95,0,0,1320,1321,7,10,0,0, + 1321,1322,7,12,0,0,1322,1323,5,95,0,0,1323,1324,7,7,0,0,1324,1325, + 7,3,0,0,1325,1326,7,23,0,0,1326,158,1,0,0,0,1327,1328,7,6,0,0,1328, + 1329,7,10,0,0,1329,1330,7,17,0,0,1330,1331,7,4,0,0,1331,1332,5,95, + 0,0,1332,1333,7,1,0,0,1333,1334,7,2,0,0,1334,1335,7,5,0,0,1335,1336, + 7,10,0,0,1336,1337,7,15,0,0,1337,1338,7,7,0,0,1338,160,1,0,0,0,1339, + 1340,7,8,0,0,1340,1341,7,15,0,0,1341,1342,7,16,0,0,1342,1343,7,2, + 0,0,1343,1344,7,4,0,0,1344,1345,7,19,0,0,1345,1346,7,3,0,0,1346, + 1347,7,14,0,0,1347,162,1,0,0,0,1348,1349,7,13,0,0,1349,1350,7,8, + 0,0,1350,1351,7,5,0,0,1351,1352,7,4,0,0,1352,1353,7,10,0,0,1353, + 1354,7,1,0,0,1354,1355,7,2,0,0,1355,1356,7,5,0,0,1356,1357,7,10, + 0,0,1357,1358,7,15,0,0,1358,1359,7,7,0,0,1359,164,1,0,0,0,1360,1361, + 7,13,0,0,1361,1362,7,8,0,0,1362,1363,7,14,0,0,1363,1364,7,14,0,0, + 1364,1365,7,8,0,0,1365,1366,7,1,0,0,1366,1367,7,2,0,0,1367,1368, + 7,5,0,0,1368,1369,7,10,0,0,1369,1370,7,15,0,0,1370,1371,7,7,0,0, + 1371,166,1,0,0,0,1372,1373,7,13,0,0,1373,1374,7,8,0,0,1374,1375, + 7,15,0,0,1375,1376,7,17,0,0,1376,1377,7,16,0,0,1377,1378,7,2,0,0, + 1378,168,1,0,0,0,1379,1380,7,13,0,0,1380,1381,7,8,0,0,1381,1382, + 7,15,0,0,1382,1383,7,17,0,0,1383,1384,7,16,0,0,1384,1385,7,2,0,0, + 1385,1386,5,95,0,0,1386,1387,7,13,0,0,1387,1388,7,8,0,0,1388,1389, + 7,5,0,0,1389,1390,7,4,0,0,1390,1391,7,10,0,0,1391,1392,7,1,0,0,1392, + 1393,7,2,0,0,1393,1394,7,5,0,0,1394,1395,7,10,0,0,1395,1396,7,15, + 0,0,1396,1397,7,7,0,0,1397,170,1,0,0,0,1398,1399,7,13,0,0,1399,1400, + 7,8,0,0,1400,1401,7,15,0,0,1401,1402,7,17,0,0,1402,1403,7,16,0,0, + 1403,1404,7,2,0,0,1404,1405,5,95,0,0,1405,1406,7,10,0,0,1406,1407, + 7,12,0,0,1407,1408,5,95,0,0,1408,1409,7,7,0,0,1409,1410,7,3,0,0, + 1410,1411,7,23,0,0,1411,172,1,0,0,0,1412,1413,7,13,0,0,1413,1414, + 7,8,0,0,1414,1415,7,15,0,0,1415,1416,7,17,0,0,1416,1417,7,16,0,0, + 1417,1418,7,2,0,0,1418,1419,5,95,0,0,1419,1420,7,10,0,0,1420,1421, + 7,12,0,0,1421,1422,5,95,0,0,1422,1423,7,6,0,0,1423,1424,7,10,0,0, + 1424,1425,7,17,0,0,1425,1426,7,4,0,0,1426,174,1,0,0,0,1427,1428, + 7,13,0,0,1428,1429,7,8,0,0,1429,1430,7,15,0,0,1430,1431,7,17,0,0, + 1431,1432,7,16,0,0,1432,1433,7,2,0,0,1433,1434,5,95,0,0,1434,1435, + 7,1,0,0,1435,1436,7,2,0,0,1436,1437,7,5,0,0,1437,1438,7,10,0,0,1438, + 1439,7,15,0,0,1439,1440,7,7,0,0,1440,176,1,0,0,0,1441,1442,7,13, + 0,0,1442,1443,7,10,0,0,1443,1444,7,15,0,0,1444,1445,7,16,0,0,1445, + 1446,7,6,0,0,1446,178,1,0,0,0,1447,1448,7,13,0,0,1448,1449,7,10, + 0,0,1449,1450,7,15,0,0,1450,1451,7,16,0,0,1451,1452,7,6,0,0,1452, + 1453,5,95,0,0,1453,1454,7,10,0,0,1454,1455,7,12,0,0,1455,1456,5, + 95,0,0,1456,1457,7,23,0,0,1457,1458,7,2,0,0,1458,1459,7,3,0,0,1459, + 1460,7,4,0,0,1460,180,1,0,0,0,1461,1462,7,25,0,0,1462,1463,7,17, + 0,0,1463,1464,7,3,0,0,1464,1465,7,4,0,0,1465,1466,7,16,0,0,1466, + 1467,7,2,0,0,1467,1468,7,4,0,0,1468,182,1,0,0,0,1469,1470,7,1,0, + 0,1470,1471,7,2,0,0,1471,1472,7,5,0,0,1472,1473,7,10,0,0,1473,1474, + 7,15,0,0,1474,1475,7,7,0,0,1475,184,1,0,0,0,1476,1477,7,1,0,0,1477, + 1478,7,2,0,0,1478,1479,7,5,0,0,1479,1480,7,10,0,0,1480,1481,7,15, + 0,0,1481,1482,7,7,0,0,1482,1483,5,95,0,0,1483,1484,7,13,0,0,1484, + 1485,7,8,0,0,1485,1486,7,5,0,0,1486,1487,7,4,0,0,1487,1488,7,10, + 0,0,1488,1489,7,1,0,0,1489,1490,7,2,0,0,1490,1491,7,5,0,0,1491,1492, + 7,10,0,0,1492,1493,7,15,0,0,1493,1494,7,7,0,0,1494,186,1,0,0,0,1495, + 1496,7,1,0,0,1496,1497,7,2,0,0,1497,1498,7,5,0,0,1498,1499,7,10, + 0,0,1499,1500,7,15,0,0,1500,1501,7,7,0,0,1501,1502,5,95,0,0,1502, + 1503,7,10,0,0,1503,1504,7,12,0,0,1504,1505,5,95,0,0,1505,1506,7, + 13,0,0,1506,1507,7,8,0,0,1507,1508,7,15,0,0,1508,1509,7,17,0,0,1509, + 1510,7,16,0,0,1510,1511,7,2,0,0,1511,188,1,0,0,0,1512,1513,7,11, + 0,0,1513,1514,7,2,0,0,1514,1515,7,2,0,0,1515,1516,7,22,0,0,1516, + 190,1,0,0,0,1517,1518,7,11,0,0,1518,1519,7,2,0,0,1519,1520,7,2,0, + 0,1520,1521,7,22,0,0,1521,1522,5,95,0,0,1522,1523,7,10,0,0,1523, + 1524,7,12,0,0,1524,1525,5,95,0,0,1525,1526,7,23,0,0,1526,1527,7, + 2,0,0,1527,1528,7,3,0,0,1528,1529,7,4,0,0,1529,192,1,0,0,0,1530, + 1531,7,23,0,0,1531,1532,7,2,0,0,1532,1533,7,3,0,0,1533,1534,7,4, + 0,0,1534,194,1,0,0,0,1535,1536,7,23,0,0,1536,1537,7,2,0,0,1537,1538, + 7,3,0,0,1538,1539,7,4,0,0,1539,1540,5,95,0,0,1540,1541,7,13,0,0, + 1541,1542,7,10,0,0,1542,1543,7,15,0,0,1543,1544,7,16,0,0,1544,1545, + 7,6,0,0,1545,196,1,0,0,0,1546,1547,7,7,0,0,1547,1548,7,3,0,0,1548, + 1549,7,16,0,0,1549,1550,7,3,0,0,1550,1551,7,13,0,0,1551,1552,7,10, + 0,0,1552,1553,7,7,0,0,1553,1554,7,2,0,0,1554,1555,7,14,0,0,1555, + 198,1,0,0,0,1556,1557,7,14,0,0,1557,1558,7,10,0,0,1558,1559,7,10, + 0,0,1559,1560,7,22,0,0,1560,1561,7,17,0,0,1561,1562,7,18,0,0,1562, + 200,1,0,0,0,1563,1564,7,1,0,0,1564,1565,7,3,0,0,1565,1566,7,19,0, + 0,1566,1567,7,2,0,0,1567,1568,7,7,0,0,1568,1569,7,1,0,0,1569,1570, + 7,2,0,0,1570,1571,7,3,0,0,1571,1572,7,4,0,0,1572,1573,7,5,0,0,1573, + 1574,7,6,0,0,1574,202,1,0,0,0,1575,1576,7,8,0,0,1576,1577,7,15,0, + 0,1577,1578,7,16,0,0,1578,204,1,0,0,0,1579,1580,7,8,0,0,1580,1581, + 7,15,0,0,1581,1582,7,16,0,0,1582,1583,7,2,0,0,1583,1584,7,20,0,0, + 1584,1585,7,2,0,0,1585,1586,7,4,0,0,1586,206,1,0,0,0,1587,1588,7, + 7,0,0,1588,1589,7,10,0,0,1589,1590,7,17,0,0,1590,1591,7,9,0,0,1591, + 1592,7,14,0,0,1592,1593,7,2,0,0,1593,208,1,0,0,0,1594,1595,7,14, + 0,0,1595,1596,7,10,0,0,1596,1597,7,15,0,0,1597,1598,7,20,0,0,1598, + 210,1,0,0,0,1599,1600,7,12,0,0,1600,1601,7,14,0,0,1601,1602,7,10, + 0,0,1602,1603,7,3,0,0,1603,1604,7,16,0,0,1604,212,1,0,0,0,1605,1606, + 7,1,0,0,1606,1607,7,16,0,0,1607,1608,7,4,0,0,1608,1609,7,8,0,0,1609, + 1610,7,15,0,0,1610,1611,7,20,0,0,1611,214,1,0,0,0,1612,1613,7,9, + 0,0,1613,1614,7,10,0,0,1614,1615,7,10,0,0,1615,1616,7,14,0,0,1616, + 1617,7,2,0,0,1617,1618,7,3,0,0,1618,1619,7,15,0,0,1619,216,1,0,0, + 0,1620,1621,5,124,0,0,1621,218,1,0,0,0,1622,1623,5,44,0,0,1623,220, + 1,0,0,0,1624,1625,5,46,0,0,1625,222,1,0,0,0,1626,1627,5,61,0,0,1627, + 224,1,0,0,0,1628,1629,5,62,0,0,1629,226,1,0,0,0,1630,1631,5,60,0, + 0,1631,228,1,0,0,0,1632,1633,5,60,0,0,1633,1634,5,61,0,0,1634,230, + 1,0,0,0,1635,1636,5,62,0,0,1636,1637,5,61,0,0,1637,232,1,0,0,0,1638, + 1639,5,33,0,0,1639,1640,5,61,0,0,1640,234,1,0,0,0,1641,1642,5,43, + 0,0,1642,236,1,0,0,0,1643,1644,5,45,0,0,1644,238,1,0,0,0,1645,1646, + 5,42,0,0,1646,240,1,0,0,0,1647,1648,5,47,0,0,1648,242,1,0,0,0,1649, + 1650,5,37,0,0,1650,244,1,0,0,0,1651,1652,5,33,0,0,1652,246,1,0,0, + 0,1653,1654,5,58,0,0,1654,248,1,0,0,0,1655,1656,5,40,0,0,1656,250, + 1,0,0,0,1657,1658,5,41,0,0,1658,252,1,0,0,0,1659,1660,5,91,0,0,1660, + 254,1,0,0,0,1661,1662,5,93,0,0,1662,256,1,0,0,0,1663,1664,5,39,0, + 0,1664,258,1,0,0,0,1665,1666,5,34,0,0,1666,260,1,0,0,0,1667,1668, + 5,96,0,0,1668,262,1,0,0,0,1669,1670,5,126,0,0,1670,264,1,0,0,0,1671, + 1672,5,38,0,0,1672,266,1,0,0,0,1673,1674,5,94,0,0,1674,268,1,0,0, + 0,1675,1676,7,3,0,0,1676,1677,7,19,0,0,1677,1678,7,20,0,0,1678,270, + 1,0,0,0,1679,1680,7,5,0,0,1680,1681,7,10,0,0,1681,1682,7,17,0,0, + 1682,1683,7,15,0,0,1683,1684,7,16,0,0,1684,272,1,0,0,0,1685,1686, + 7,7,0,0,1686,1687,7,8,0,0,1687,1688,7,1,0,0,1688,1689,7,16,0,0,1689, + 1690,7,8,0,0,1690,1691,7,15,0,0,1691,1692,7,5,0,0,1692,1693,7,16, + 0,0,1693,1694,5,95,0,0,1694,1695,7,5,0,0,1695,1696,7,10,0,0,1696, + 1697,7,17,0,0,1697,1698,7,15,0,0,1698,1699,7,16,0,0,1699,274,1,0, + 0,0,1700,1701,7,2,0,0,1701,1702,7,1,0,0,1702,1703,7,16,0,0,1703, + 1704,7,7,0,0,1704,1705,7,5,0,0,1705,276,1,0,0,0,1706,1707,7,2,0, + 0,1707,1708,7,1,0,0,1708,1709,7,16,0,0,1709,1710,7,7,0,0,1710,1711, + 7,5,0,0,1711,1712,5,95,0,0,1712,1713,7,2,0,0,1713,1714,7,4,0,0,1714, + 1715,7,4,0,0,1715,1716,7,10,0,0,1716,1717,7,4,0,0,1717,278,1,0,0, + 0,1718,1719,7,13,0,0,1719,1720,7,3,0,0,1720,1721,7,21,0,0,1721,280, + 1,0,0,0,1722,1723,7,13,0,0,1723,1724,7,2,0,0,1724,1725,7,3,0,0,1725, + 1726,7,15,0,0,1726,282,1,0,0,0,1727,1728,7,13,0,0,1728,1729,7,2, + 0,0,1729,1730,7,7,0,0,1730,1731,7,8,0,0,1731,1732,7,3,0,0,1732,1733, + 7,15,0,0,1733,284,1,0,0,0,1734,1735,7,13,0,0,1735,1736,7,8,0,0,1736, + 1737,7,15,0,0,1737,286,1,0,0,0,1738,1739,7,13,0,0,1739,1740,7,10, + 0,0,1740,1741,7,7,0,0,1741,1742,7,2,0,0,1742,288,1,0,0,0,1743,1744, + 7,4,0,0,1744,1745,7,3,0,0,1745,1746,7,15,0,0,1746,1747,7,20,0,0, + 1747,1748,7,2,0,0,1748,290,1,0,0,0,1749,1750,7,1,0,0,1750,1751,7, + 16,0,0,1751,1752,7,7,0,0,1752,1753,7,2,0,0,1753,1754,7,19,0,0,1754, + 292,1,0,0,0,1755,1756,7,1,0,0,1756,1757,7,16,0,0,1757,1758,7,7,0, + 0,1758,1759,7,2,0,0,1759,1760,7,19,0,0,1760,1761,7,18,0,0,1761,294, + 1,0,0,0,1762,1763,7,1,0,0,1763,1764,7,17,0,0,1764,1765,7,13,0,0, + 1765,296,1,0,0,0,1766,1767,7,1,0,0,1767,1768,7,17,0,0,1768,1769, + 7,13,0,0,1769,1770,7,1,0,0,1770,1771,7,25,0,0,1771,298,1,0,0,0,1772, + 1773,7,19,0,0,1773,1774,7,3,0,0,1774,1775,7,4,0,0,1775,1776,5,95, + 0,0,1776,1777,7,1,0,0,1777,1778,7,3,0,0,1778,1779,7,13,0,0,1779, + 1780,7,18,0,0,1780,300,1,0,0,0,1781,1782,7,19,0,0,1782,1783,7,3, + 0,0,1783,1784,7,4,0,0,1784,1785,5,95,0,0,1785,1786,7,18,0,0,1786, + 1787,7,10,0,0,1787,1788,7,18,0,0,1788,302,1,0,0,0,1789,1790,7,1, + 0,0,1790,1791,7,16,0,0,1791,1792,7,7,0,0,1792,1793,7,7,0,0,1793, + 1794,7,2,0,0,1794,1795,7,19,0,0,1795,1796,5,95,0,0,1796,1797,7,1, + 0,0,1797,1798,7,3,0,0,1798,1799,7,13,0,0,1799,1800,7,18,0,0,1800, + 304,1,0,0,0,1801,1802,7,1,0,0,1802,1803,7,16,0,0,1803,1804,7,7,0, + 0,1804,1805,7,7,0,0,1805,1806,7,2,0,0,1806,1807,7,19,0,0,1807,1808, + 5,95,0,0,1808,1809,7,18,0,0,1809,1810,7,10,0,0,1810,1811,7,18,0, + 0,1811,306,1,0,0,0,1812,1813,7,18,0,0,1813,1814,7,2,0,0,1814,1815, + 7,4,0,0,1815,1816,7,5,0,0,1816,1817,7,2,0,0,1817,1818,7,15,0,0,1818, + 1819,7,16,0,0,1819,1820,7,8,0,0,1820,1821,7,14,0,0,1821,1822,7,2, + 0,0,1822,308,1,0,0,0,1823,1824,7,16,0,0,1824,1825,7,3,0,0,1825,1826, + 7,22,0,0,1826,1827,7,2,0,0,1827,310,1,0,0,0,1828,1829,7,12,0,0,1829, + 1830,7,8,0,0,1830,1831,7,4,0,0,1831,1832,7,1,0,0,1832,1833,7,16, + 0,0,1833,312,1,0,0,0,1834,1835,7,14,0,0,1835,1836,7,3,0,0,1836,1837, + 7,1,0,0,1837,1838,7,16,0,0,1838,314,1,0,0,0,1839,1840,7,14,0,0,1840, + 1841,7,8,0,0,1841,1842,7,1,0,0,1842,1843,7,16,0,0,1843,316,1,0,0, + 0,1844,1845,7,19,0,0,1845,1846,7,3,0,0,1846,1847,7,14,0,0,1847,1848, + 7,17,0,0,1848,1849,7,2,0,0,1849,1850,7,1,0,0,1850,318,1,0,0,0,1851, + 1852,7,2,0,0,1852,1853,7,3,0,0,1853,1854,7,4,0,0,1854,1855,7,14, + 0,0,1855,1856,7,8,0,0,1856,1857,7,2,0,0,1857,1858,7,1,0,0,1858,1859, + 7,16,0,0,1859,320,1,0,0,0,1860,1861,7,2,0,0,1861,1862,7,3,0,0,1862, + 1863,7,4,0,0,1863,1864,7,14,0,0,1864,1865,7,8,0,0,1865,1866,7,2, + 0,0,1866,1867,7,1,0,0,1867,1868,7,16,0,0,1868,1869,5,95,0,0,1869, + 1870,7,16,0,0,1870,1871,7,8,0,0,1871,1872,7,13,0,0,1872,1873,7,2, + 0,0,1873,322,1,0,0,0,1874,1875,7,14,0,0,1875,1876,7,3,0,0,1876,1877, + 7,16,0,0,1877,1878,7,2,0,0,1878,1879,7,1,0,0,1879,1880,7,16,0,0, + 1880,324,1,0,0,0,1881,1882,7,14,0,0,1882,1883,7,3,0,0,1883,1884, + 7,16,0,0,1884,1885,7,2,0,0,1885,1886,7,1,0,0,1886,1887,7,16,0,0, + 1887,1888,5,95,0,0,1888,1889,7,16,0,0,1889,1890,7,8,0,0,1890,1891, + 7,13,0,0,1891,1892,7,2,0,0,1892,326,1,0,0,0,1893,1894,7,18,0,0,1894, + 1895,7,2,0,0,1895,1896,7,4,0,0,1896,1897,5,95,0,0,1897,1898,7,7, + 0,0,1898,1899,7,3,0,0,1899,1900,7,23,0,0,1900,328,1,0,0,0,1901,1902, + 7,18,0,0,1902,1903,7,2,0,0,1903,1904,7,4,0,0,1904,1905,5,95,0,0, + 1905,1906,7,6,0,0,1906,1907,7,10,0,0,1907,1908,7,17,0,0,1908,1909, + 7,4,0,0,1909,330,1,0,0,0,1910,1911,7,18,0,0,1911,1912,7,2,0,0,1912, + 1913,7,4,0,0,1913,1914,5,95,0,0,1914,1915,7,13,0,0,1915,1916,7,8, + 0,0,1916,1917,7,15,0,0,1917,1918,7,17,0,0,1918,1919,7,16,0,0,1919, + 1920,7,2,0,0,1920,332,1,0,0,0,1921,1922,7,18,0,0,1922,1923,7,2,0, + 0,1923,1924,7,4,0,0,1924,1925,5,95,0,0,1925,1926,7,1,0,0,1926,1927, + 7,2,0,0,1927,1928,7,5,0,0,1928,1929,7,10,0,0,1929,1930,7,15,0,0, + 1930,1931,7,7,0,0,1931,334,1,0,0,0,1932,1933,7,4,0,0,1933,1934,7, + 3,0,0,1934,1935,7,16,0,0,1935,1936,7,2,0,0,1936,336,1,0,0,0,1937, + 1938,7,1,0,0,1938,1939,7,18,0,0,1939,1940,7,3,0,0,1940,1941,7,4, + 0,0,1941,1942,7,22,0,0,1942,1943,7,14,0,0,1943,1944,7,8,0,0,1944, + 1945,7,15,0,0,1945,1946,7,2,0,0,1946,338,1,0,0,0,1947,1948,7,5,0, + 0,1948,340,1,0,0,0,1949,1950,7,7,0,0,1950,1951,7,5,0,0,1951,342, + 1,0,0,0,1952,1953,7,3,0,0,1953,1954,7,9,0,0,1954,1955,7,1,0,0,1955, + 344,1,0,0,0,1956,1957,7,5,0,0,1957,1958,7,9,0,0,1958,1959,7,4,0, + 0,1959,1960,7,16,0,0,1960,346,1,0,0,0,1961,1962,7,5,0,0,1962,1963, + 7,2,0,0,1963,1964,7,8,0,0,1964,1965,7,14,0,0,1965,348,1,0,0,0,1966, + 1967,7,5,0,0,1967,1968,7,2,0,0,1968,1969,7,8,0,0,1969,1970,7,14, + 0,0,1970,1971,7,8,0,0,1971,1972,7,15,0,0,1972,1973,7,20,0,0,1973, + 350,1,0,0,0,1974,1975,7,5,0,0,1975,1976,7,10,0,0,1976,1977,7,15, + 0,0,1977,1978,7,19,0,0,1978,352,1,0,0,0,1979,1980,7,5,0,0,1980,1981, + 7,4,0,0,1981,1982,7,5,0,0,1982,1983,5,51,0,0,1983,1984,5,50,0,0, + 1984,354,1,0,0,0,1985,1986,7,2,0,0,1986,356,1,0,0,0,1987,1988,7, + 2,0,0,1988,1989,7,21,0,0,1989,1990,7,18,0,0,1990,358,1,0,0,0,1991, + 1992,7,12,0,0,1992,1993,7,14,0,0,1993,1994,7,10,0,0,1994,1995,7, + 10,0,0,1995,1996,7,4,0,0,1996,360,1,0,0,0,1997,1998,7,14,0,0,1998, + 1999,7,15,0,0,1999,362,1,0,0,0,2000,2001,7,14,0,0,2001,2002,7,10, + 0,0,2002,2003,7,20,0,0,2003,364,1,0,0,0,2004,2005,7,14,0,0,2005, + 2006,7,10,0,0,2006,2007,7,20,0,0,2007,2008,5,49,0,0,2008,2009,5, + 48,0,0,2009,366,1,0,0,0,2010,2011,7,14,0,0,2011,2012,7,10,0,0,2012, + 2013,7,20,0,0,2013,2014,5,50,0,0,2014,368,1,0,0,0,2015,2016,7,13, + 0,0,2016,2017,7,10,0,0,2017,2018,7,7,0,0,2018,370,1,0,0,0,2019,2020, + 7,18,0,0,2020,2021,7,8,0,0,2021,372,1,0,0,0,2022,2023,7,18,0,0,2023, + 2024,7,10,0,0,2024,2025,7,1,0,0,2025,2026,7,8,0,0,2026,2027,7,16, + 0,0,2027,2028,7,8,0,0,2028,2029,7,10,0,0,2029,2030,7,15,0,0,2030, + 374,1,0,0,0,2031,2032,7,18,0,0,2032,2033,7,10,0,0,2033,2034,7,11, + 0,0,2034,376,1,0,0,0,2035,2036,7,18,0,0,2036,2037,7,10,0,0,2037, + 2038,7,11,0,0,2038,2039,7,2,0,0,2039,2040,7,4,0,0,2040,378,1,0,0, + 0,2041,2042,7,4,0,0,2042,2043,7,3,0,0,2043,2044,7,15,0,0,2044,2045, + 7,7,0,0,2045,380,1,0,0,0,2046,2047,7,4,0,0,2047,2048,7,10,0,0,2048, + 2049,7,17,0,0,2049,2050,7,15,0,0,2050,2051,7,7,0,0,2051,382,1,0, + 0,0,2052,2053,7,1,0,0,2053,2054,7,8,0,0,2054,2055,7,20,0,0,2055, + 2056,7,15,0,0,2056,384,1,0,0,0,2057,2058,7,1,0,0,2058,2059,7,25, + 0,0,2059,2060,7,4,0,0,2060,2061,7,16,0,0,2061,386,1,0,0,0,2062,2063, + 7,16,0,0,2063,2064,7,4,0,0,2064,2065,7,17,0,0,2065,2066,7,15,0,0, + 2066,2067,7,5,0,0,2067,2068,7,3,0,0,2068,2069,7,16,0,0,2069,2070, + 7,2,0,0,2070,388,1,0,0,0,2071,2072,7,3,0,0,2072,2073,7,5,0,0,2073, + 2074,7,10,0,0,2074,2075,7,1,0,0,2075,390,1,0,0,0,2076,2077,7,3,0, + 0,2077,2078,7,1,0,0,2078,2079,7,8,0,0,2079,2080,7,15,0,0,2080,392, + 1,0,0,0,2081,2082,7,3,0,0,2082,2083,7,16,0,0,2083,2084,7,3,0,0,2084, + 2085,7,15,0,0,2085,394,1,0,0,0,2086,2087,7,3,0,0,2087,2088,7,16, + 0,0,2088,2089,7,3,0,0,2089,2090,7,15,0,0,2090,2091,5,50,0,0,2091, + 396,1,0,0,0,2092,2093,7,5,0,0,2093,2094,7,10,0,0,2094,2095,7,1,0, + 0,2095,398,1,0,0,0,2096,2097,7,5,0,0,2097,2098,7,10,0,0,2098,2099, + 7,16,0,0,2099,400,1,0,0,0,2100,2101,7,7,0,0,2101,2102,7,2,0,0,2102, + 2103,7,20,0,0,2103,2104,7,4,0,0,2104,2105,7,2,0,0,2105,2106,7,2, + 0,0,2106,2107,7,1,0,0,2107,402,1,0,0,0,2108,2109,7,4,0,0,2109,2110, + 7,3,0,0,2110,2111,7,7,0,0,2111,2112,7,8,0,0,2112,2113,7,3,0,0,2113, + 2114,7,15,0,0,2114,2115,7,1,0,0,2115,404,1,0,0,0,2116,2117,7,1,0, + 0,2117,2118,7,8,0,0,2118,2119,7,15,0,0,2119,406,1,0,0,0,2120,2121, + 7,16,0,0,2121,2122,7,3,0,0,2122,2123,7,15,0,0,2123,408,1,0,0,0,2124, + 2125,7,3,0,0,2125,2126,7,7,0,0,2126,2127,7,7,0,0,2127,2128,7,7,0, + 0,2128,2129,7,3,0,0,2129,2130,7,16,0,0,2130,2131,7,2,0,0,2131,410, + 1,0,0,0,2132,2133,7,3,0,0,2133,2134,7,7,0,0,2134,2135,7,7,0,0,2135, + 2136,7,16,0,0,2136,2137,7,8,0,0,2137,2138,7,13,0,0,2138,2139,7,2, + 0,0,2139,412,1,0,0,0,2140,2141,7,5,0,0,2141,2142,7,17,0,0,2142,2143, + 7,4,0,0,2143,2144,7,7,0,0,2144,2145,7,3,0,0,2145,2146,7,16,0,0,2146, + 2147,7,2,0,0,2147,414,1,0,0,0,2148,2149,7,5,0,0,2149,2150,7,17,0, + 0,2150,2151,7,4,0,0,2151,2152,7,4,0,0,2152,2153,7,2,0,0,2153,2154, + 7,15,0,0,2154,2155,7,16,0,0,2155,2156,5,95,0,0,2156,2157,7,7,0,0, + 2157,2158,7,3,0,0,2158,2159,7,16,0,0,2159,2160,7,2,0,0,2160,416, + 1,0,0,0,2161,2162,7,5,0,0,2162,2163,7,17,0,0,2163,2164,7,4,0,0,2164, + 2165,7,4,0,0,2165,2166,7,2,0,0,2166,2167,7,15,0,0,2167,2168,7,16, + 0,0,2168,2169,5,95,0,0,2169,2170,7,16,0,0,2170,2171,7,8,0,0,2171, + 2172,7,13,0,0,2172,2173,7,2,0,0,2173,418,1,0,0,0,2174,2175,7,5,0, + 0,2175,2176,7,17,0,0,2176,2177,7,4,0,0,2177,2178,7,4,0,0,2178,2179, + 7,2,0,0,2179,2180,7,15,0,0,2180,2181,7,16,0,0,2181,2182,5,95,0,0, + 2182,2183,7,16,0,0,2183,2184,7,8,0,0,2184,2185,7,13,0,0,2185,2186, + 7,2,0,0,2186,2187,7,1,0,0,2187,2188,7,16,0,0,2188,2189,7,3,0,0,2189, + 2190,7,13,0,0,2190,2191,7,18,0,0,2191,420,1,0,0,0,2192,2193,7,5, + 0,0,2193,2194,7,17,0,0,2194,2195,7,4,0,0,2195,2196,7,16,0,0,2196, + 2197,7,8,0,0,2197,2198,7,13,0,0,2198,2199,7,2,0,0,2199,422,1,0,0, + 0,2200,2201,7,7,0,0,2201,2202,7,3,0,0,2202,2203,7,16,0,0,2203,2204, + 7,2,0,0,2204,424,1,0,0,0,2205,2206,7,7,0,0,2206,2207,7,3,0,0,2207, + 2208,7,16,0,0,2208,2209,7,2,0,0,2209,2210,7,7,0,0,2210,2211,7,8, + 0,0,2211,2212,7,12,0,0,2212,2213,7,12,0,0,2213,426,1,0,0,0,2214, + 2215,7,7,0,0,2215,2216,7,3,0,0,2216,2217,7,16,0,0,2217,2218,7,2, + 0,0,2218,2219,5,95,0,0,2219,2220,7,3,0,0,2220,2221,7,7,0,0,2221, + 2222,7,7,0,0,2222,428,1,0,0,0,2223,2224,7,7,0,0,2224,2225,7,3,0, + 0,2225,2226,7,16,0,0,2226,2227,7,2,0,0,2227,2228,5,95,0,0,2228,2229, + 7,12,0,0,2229,2230,7,10,0,0,2230,2231,7,4,0,0,2231,2232,7,13,0,0, + 2232,2233,7,3,0,0,2233,2234,7,16,0,0,2234,430,1,0,0,0,2235,2236, + 7,7,0,0,2236,2237,7,3,0,0,2237,2238,7,16,0,0,2238,2239,7,2,0,0,2239, + 2240,5,95,0,0,2240,2241,7,1,0,0,2241,2242,7,17,0,0,2242,2243,7,9, + 0,0,2243,432,1,0,0,0,2244,2245,7,7,0,0,2245,2246,7,3,0,0,2246,2247, + 7,23,0,0,2247,2248,7,15,0,0,2248,2249,7,3,0,0,2249,2250,7,13,0,0, + 2250,2251,7,2,0,0,2251,434,1,0,0,0,2252,2253,7,7,0,0,2253,2254,7, + 3,0,0,2254,2255,7,23,0,0,2255,2256,7,10,0,0,2256,2257,7,12,0,0,2257, + 2258,7,13,0,0,2258,2259,7,10,0,0,2259,2260,7,15,0,0,2260,2261,7, + 16,0,0,2261,2262,7,6,0,0,2262,436,1,0,0,0,2263,2264,7,7,0,0,2264, + 2265,7,3,0,0,2265,2266,7,23,0,0,2266,2267,7,10,0,0,2267,2268,7,12, + 0,0,2268,2269,7,11,0,0,2269,2270,7,2,0,0,2270,2271,7,2,0,0,2271, + 2272,7,22,0,0,2272,438,1,0,0,0,2273,2274,7,7,0,0,2274,2275,7,3,0, + 0,2275,2276,7,23,0,0,2276,2277,7,10,0,0,2277,2278,7,12,0,0,2278, + 2279,7,23,0,0,2279,2280,7,2,0,0,2280,2281,7,3,0,0,2281,2282,7,4, + 0,0,2282,440,1,0,0,0,2283,2284,7,7,0,0,2284,2285,7,3,0,0,2285,2286, + 7,23,0,0,2286,2287,5,95,0,0,2287,2288,7,10,0,0,2288,2289,7,12,0, + 0,2289,2290,5,95,0,0,2290,2291,7,13,0,0,2291,2292,7,10,0,0,2292, + 2293,7,15,0,0,2293,2294,7,16,0,0,2294,2295,7,6,0,0,2295,442,1,0, + 0,0,2296,2297,7,7,0,0,2297,2298,7,3,0,0,2298,2299,7,23,0,0,2299, + 2300,5,95,0,0,2300,2301,7,10,0,0,2301,2302,7,12,0,0,2302,2303,5, + 95,0,0,2303,2304,7,11,0,0,2304,2305,7,2,0,0,2305,2306,7,2,0,0,2306, + 2307,7,22,0,0,2307,444,1,0,0,0,2308,2309,7,2,0,0,2309,2310,7,21, + 0,0,2310,2311,7,16,0,0,2311,2312,7,4,0,0,2312,2313,7,3,0,0,2313, + 2314,7,5,0,0,2314,2315,7,16,0,0,2315,446,1,0,0,0,2316,2317,7,12, + 0,0,2317,2318,7,4,0,0,2318,2319,7,10,0,0,2319,2320,7,13,0,0,2320, + 2321,5,95,0,0,2321,2322,7,7,0,0,2322,2323,7,3,0,0,2323,2324,7,23, + 0,0,2324,2325,7,1,0,0,2325,448,1,0,0,0,2326,2327,7,12,0,0,2327,2328, + 7,4,0,0,2328,2329,7,10,0,0,2329,2330,7,13,0,0,2330,2331,5,95,0,0, + 2331,2332,7,17,0,0,2332,2333,7,15,0,0,2333,2334,7,8,0,0,2334,2335, + 7,21,0,0,2335,2336,7,16,0,0,2336,2337,7,8,0,0,2337,2338,7,13,0,0, + 2338,2339,7,2,0,0,2339,450,1,0,0,0,2340,2341,7,20,0,0,2341,2342, + 7,2,0,0,2342,2343,7,16,0,0,2343,2344,5,95,0,0,2344,2345,7,12,0,0, + 2345,2346,7,10,0,0,2346,2347,7,4,0,0,2347,2348,7,13,0,0,2348,2349, + 7,3,0,0,2349,2350,7,16,0,0,2350,452,1,0,0,0,2351,2352,7,14,0,0,2352, + 2353,7,3,0,0,2353,2354,7,1,0,0,2354,2355,7,16,0,0,2355,2356,5,95, + 0,0,2356,2357,7,7,0,0,2357,2358,7,3,0,0,2358,2359,7,23,0,0,2359, + 454,1,0,0,0,2360,2361,7,14,0,0,2361,2362,7,10,0,0,2362,2363,7,5, + 0,0,2363,2364,7,3,0,0,2364,2365,7,14,0,0,2365,2366,7,16,0,0,2366, + 2367,7,8,0,0,2367,2368,7,13,0,0,2368,2369,7,2,0,0,2369,456,1,0,0, + 0,2370,2371,7,14,0,0,2371,2372,7,10,0,0,2372,2373,7,5,0,0,2373,2374, + 7,3,0,0,2374,2375,7,14,0,0,2375,2376,7,16,0,0,2376,2377,7,8,0,0, + 2377,2378,7,13,0,0,2378,2379,7,2,0,0,2379,2380,7,1,0,0,2380,2381, + 7,16,0,0,2381,2382,7,3,0,0,2382,2383,7,13,0,0,2383,2384,7,18,0,0, + 2384,458,1,0,0,0,2385,2386,7,13,0,0,2386,2387,7,3,0,0,2387,2388, + 7,22,0,0,2388,2389,7,2,0,0,2389,2390,7,7,0,0,2390,2391,7,3,0,0,2391, + 2392,7,16,0,0,2392,2393,7,2,0,0,2393,460,1,0,0,0,2394,2395,7,13, + 0,0,2395,2396,7,3,0,0,2396,2397,7,22,0,0,2397,2398,7,2,0,0,2398, + 2399,7,16,0,0,2399,2400,7,8,0,0,2400,2401,7,13,0,0,2401,2402,7,2, + 0,0,2402,462,1,0,0,0,2403,2404,7,13,0,0,2404,2405,7,10,0,0,2405, + 2406,7,15,0,0,2406,2407,7,16,0,0,2407,2408,7,6,0,0,2408,2409,7,15, + 0,0,2409,2410,7,3,0,0,2410,2411,7,13,0,0,2411,2412,7,2,0,0,2412, + 464,1,0,0,0,2413,2414,7,15,0,0,2414,2415,7,10,0,0,2415,2416,7,11, + 0,0,2416,466,1,0,0,0,2417,2418,7,18,0,0,2418,2419,7,2,0,0,2419,2420, + 7,4,0,0,2420,2421,7,8,0,0,2421,2422,7,10,0,0,2422,2423,7,7,0,0,2423, + 2424,5,95,0,0,2424,2425,7,3,0,0,2425,2426,7,7,0,0,2426,2427,7,7, + 0,0,2427,468,1,0,0,0,2428,2429,7,18,0,0,2429,2430,7,2,0,0,2430,2431, + 7,4,0,0,2431,2432,7,8,0,0,2432,2433,7,10,0,0,2433,2434,7,7,0,0,2434, + 2435,5,95,0,0,2435,2436,7,7,0,0,2436,2437,7,8,0,0,2437,2438,7,12, + 0,0,2438,2439,7,12,0,0,2439,470,1,0,0,0,2440,2441,7,1,0,0,2441,2442, + 7,2,0,0,2442,2443,7,5,0,0,2443,2444,5,95,0,0,2444,2445,7,16,0,0, + 2445,2446,7,10,0,0,2446,2447,5,95,0,0,2447,2448,7,16,0,0,2448,2449, + 7,8,0,0,2449,2450,7,13,0,0,2450,2451,7,2,0,0,2451,472,1,0,0,0,2452, + 2453,7,1,0,0,2453,2454,7,16,0,0,2454,2455,7,4,0,0,2455,2456,5,95, + 0,0,2456,2457,7,16,0,0,2457,2458,7,10,0,0,2458,2459,5,95,0,0,2459, + 2460,7,7,0,0,2460,2461,7,3,0,0,2461,2462,7,16,0,0,2462,2463,7,2, + 0,0,2463,474,1,0,0,0,2464,2465,7,1,0,0,2465,2466,7,17,0,0,2466,2467, + 7,9,0,0,2467,2468,7,7,0,0,2468,2469,7,3,0,0,2469,2470,7,16,0,0,2470, + 2471,7,2,0,0,2471,476,1,0,0,0,2472,2473,7,1,0,0,2473,2474,7,17,0, + 0,2474,2475,7,9,0,0,2475,2476,7,16,0,0,2476,2477,7,8,0,0,2477,2478, + 7,13,0,0,2478,2479,7,2,0,0,2479,478,1,0,0,0,2480,2481,7,1,0,0,2481, + 2482,7,23,0,0,2482,2483,7,1,0,0,2483,2484,7,7,0,0,2484,2485,7,3, + 0,0,2485,2486,7,16,0,0,2486,2487,7,2,0,0,2487,480,1,0,0,0,2488,2489, + 7,16,0,0,2489,2490,7,8,0,0,2490,2491,7,13,0,0,2491,2492,7,2,0,0, + 2492,482,1,0,0,0,2493,2494,7,16,0,0,2494,2495,7,8,0,0,2495,2496, + 7,13,0,0,2496,2497,7,2,0,0,2497,2498,7,7,0,0,2498,2499,7,8,0,0,2499, + 2500,7,12,0,0,2500,2501,7,12,0,0,2501,484,1,0,0,0,2502,2503,7,16, + 0,0,2503,2504,7,8,0,0,2504,2505,7,13,0,0,2505,2506,7,2,0,0,2506, + 2507,7,1,0,0,2507,2508,7,16,0,0,2508,2509,7,3,0,0,2509,2510,7,13, + 0,0,2510,2511,7,18,0,0,2511,486,1,0,0,0,2512,2513,7,16,0,0,2513, + 2514,7,8,0,0,2514,2515,7,13,0,0,2515,2516,7,2,0,0,2516,2517,7,1, + 0,0,2517,2518,7,16,0,0,2518,2519,7,3,0,0,2519,2520,7,13,0,0,2520, + 2521,7,18,0,0,2521,2522,7,3,0,0,2522,2523,7,7,0,0,2523,2524,7,7, + 0,0,2524,488,1,0,0,0,2525,2526,7,16,0,0,2526,2527,7,8,0,0,2527,2528, + 7,13,0,0,2528,2529,7,2,0,0,2529,2530,7,1,0,0,2530,2531,7,16,0,0, + 2531,2532,7,3,0,0,2532,2533,7,13,0,0,2533,2534,7,18,0,0,2534,2535, + 7,7,0,0,2535,2536,7,8,0,0,2536,2537,7,12,0,0,2537,2538,7,12,0,0, + 2538,490,1,0,0,0,2539,2540,7,16,0,0,2540,2541,7,8,0,0,2541,2542, + 7,13,0,0,2542,2543,7,2,0,0,2543,2544,5,95,0,0,2544,2545,7,12,0,0, + 2545,2546,7,10,0,0,2546,2547,7,4,0,0,2547,2548,7,13,0,0,2548,2549, + 7,3,0,0,2549,2550,7,16,0,0,2550,492,1,0,0,0,2551,2552,7,16,0,0,2552, + 2553,7,8,0,0,2553,2554,7,13,0,0,2554,2555,7,2,0,0,2555,2556,5,95, + 0,0,2556,2557,7,16,0,0,2557,2558,7,10,0,0,2558,2559,5,95,0,0,2559, + 2560,7,1,0,0,2560,2561,7,2,0,0,2561,2562,7,5,0,0,2562,494,1,0,0, + 0,2563,2564,7,16,0,0,2564,2565,7,10,0,0,2565,2566,5,95,0,0,2566, + 2567,7,7,0,0,2567,2568,7,3,0,0,2568,2569,7,23,0,0,2569,2570,7,1, + 0,0,2570,496,1,0,0,0,2571,2572,7,16,0,0,2572,2573,7,10,0,0,2573, + 2574,5,95,0,0,2574,2575,7,1,0,0,2575,2576,7,2,0,0,2576,2577,7,5, + 0,0,2577,2578,7,10,0,0,2578,2579,7,15,0,0,2579,2580,7,7,0,0,2580, + 2581,7,1,0,0,2581,498,1,0,0,0,2582,2583,7,17,0,0,2583,2584,7,15, + 0,0,2584,2585,7,8,0,0,2585,2586,7,21,0,0,2586,2587,5,95,0,0,2587, + 2588,7,16,0,0,2588,2589,7,8,0,0,2589,2590,7,13,0,0,2590,2591,7,2, + 0,0,2591,2592,7,1,0,0,2592,2593,7,16,0,0,2593,2594,7,3,0,0,2594, + 2595,7,13,0,0,2595,2596,7,18,0,0,2596,500,1,0,0,0,2597,2598,7,17, + 0,0,2598,2599,7,16,0,0,2599,2600,7,5,0,0,2600,2601,5,95,0,0,2601, + 2602,7,7,0,0,2602,2603,7,3,0,0,2603,2604,7,16,0,0,2604,2605,7,2, + 0,0,2605,502,1,0,0,0,2606,2607,7,17,0,0,2607,2608,7,16,0,0,2608, + 2609,7,5,0,0,2609,2610,5,95,0,0,2610,2611,7,16,0,0,2611,2612,7,8, + 0,0,2612,2613,7,13,0,0,2613,2614,7,2,0,0,2614,504,1,0,0,0,2615,2616, + 7,17,0,0,2616,2617,7,16,0,0,2617,2618,7,5,0,0,2618,2619,5,95,0,0, + 2619,2620,7,16,0,0,2620,2621,7,8,0,0,2621,2622,7,13,0,0,2622,2623, + 7,2,0,0,2623,2624,7,1,0,0,2624,2625,7,16,0,0,2625,2626,7,3,0,0,2626, + 2627,7,13,0,0,2627,2628,7,18,0,0,2628,506,1,0,0,0,2629,2630,7,11, + 0,0,2630,2631,7,2,0,0,2631,2632,7,2,0,0,2632,2633,7,22,0,0,2633, + 2634,7,7,0,0,2634,2635,7,3,0,0,2635,2636,7,23,0,0,2636,508,1,0,0, + 0,2637,2638,7,23,0,0,2638,2639,7,2,0,0,2639,2640,7,3,0,0,2640,2641, + 7,4,0,0,2641,2642,7,11,0,0,2642,2643,7,2,0,0,2643,2644,7,2,0,0,2644, + 2645,7,22,0,0,2645,510,1,0,0,0,2646,2647,7,1,0,0,2647,2648,7,17, + 0,0,2648,2649,7,9,0,0,2649,2650,7,1,0,0,2650,2651,7,16,0,0,2651, + 2652,7,4,0,0,2652,512,1,0,0,0,2653,2654,7,1,0,0,2654,2655,7,17,0, + 0,2655,2656,7,9,0,0,2656,2657,7,1,0,0,2657,2658,7,16,0,0,2658,2659, + 7,4,0,0,2659,2660,7,8,0,0,2660,2661,7,15,0,0,2661,2662,7,20,0,0, + 2662,514,1,0,0,0,2663,2664,7,14,0,0,2664,2665,7,16,0,0,2665,2666, + 7,4,0,0,2666,2667,7,8,0,0,2667,2668,7,13,0,0,2668,516,1,0,0,0,2669, + 2670,7,4,0,0,2670,2671,7,16,0,0,2671,2672,7,4,0,0,2672,2673,7,8, + 0,0,2673,2674,7,13,0,0,2674,518,1,0,0,0,2675,2676,7,16,0,0,2676, + 2677,7,4,0,0,2677,2678,7,8,0,0,2678,2679,7,13,0,0,2679,520,1,0,0, + 0,2680,2681,7,16,0,0,2681,2682,7,10,0,0,2682,522,1,0,0,0,2683,2684, + 7,14,0,0,2684,2685,7,10,0,0,2685,2686,7,11,0,0,2686,2687,7,2,0,0, + 2687,2688,7,4,0,0,2688,524,1,0,0,0,2689,2690,7,17,0,0,2690,2691, + 7,18,0,0,2691,2692,7,18,0,0,2692,2693,7,2,0,0,2693,2694,7,4,0,0, + 2694,526,1,0,0,0,2695,2696,7,5,0,0,2696,2697,7,10,0,0,2697,2698, + 7,15,0,0,2698,2699,7,5,0,0,2699,2700,7,3,0,0,2700,2701,7,16,0,0, + 2701,528,1,0,0,0,2702,2703,7,5,0,0,2703,2704,7,10,0,0,2704,2705, + 7,15,0,0,2705,2706,7,5,0,0,2706,2707,7,3,0,0,2707,2708,7,16,0,0, + 2708,2709,5,95,0,0,2709,2710,7,11,0,0,2710,2711,7,1,0,0,2711,530, + 1,0,0,0,2712,2713,7,14,0,0,2713,2714,7,2,0,0,2714,2715,7,15,0,0, + 2715,2716,7,20,0,0,2716,2717,7,16,0,0,2717,2718,7,6,0,0,2718,532, + 1,0,0,0,2719,2720,7,1,0,0,2720,2721,7,16,0,0,2721,2722,7,4,0,0,2722, + 2723,7,5,0,0,2723,2724,7,13,0,0,2724,2725,7,18,0,0,2725,534,1,0, + 0,0,2726,2727,7,4,0,0,2727,2728,7,8,0,0,2728,2729,7,20,0,0,2729, + 2730,7,6,0,0,2730,2731,7,16,0,0,2731,536,1,0,0,0,2732,2733,7,14, + 0,0,2733,2734,7,2,0,0,2734,2735,7,12,0,0,2735,2736,7,16,0,0,2736, + 538,1,0,0,0,2737,2738,7,3,0,0,2738,2739,7,1,0,0,2739,2740,7,5,0, + 0,2740,2741,7,8,0,0,2741,2742,7,8,0,0,2742,540,1,0,0,0,2743,2744, + 7,14,0,0,2744,2745,7,10,0,0,2745,2746,7,5,0,0,2746,2747,7,3,0,0, + 2747,2748,7,16,0,0,2748,2749,7,2,0,0,2749,542,1,0,0,0,2750,2751, + 7,4,0,0,2751,2752,7,2,0,0,2752,2753,7,18,0,0,2753,2754,7,14,0,0, + 2754,2755,7,3,0,0,2755,2756,7,5,0,0,2756,2757,7,2,0,0,2757,544,1, + 0,0,0,2758,2759,7,4,0,0,2759,2760,7,2,0,0,2760,2761,7,19,0,0,2761, + 2762,7,2,0,0,2762,2763,7,4,0,0,2763,2764,7,1,0,0,2764,2765,7,2,0, + 0,2765,546,1,0,0,0,2766,2767,7,5,0,0,2767,2768,7,3,0,0,2768,2769, + 7,1,0,0,2769,2770,7,16,0,0,2770,548,1,0,0,0,2771,2772,7,14,0,0,2772, + 2773,7,8,0,0,2773,2774,7,22,0,0,2774,2775,7,2,0,0,2775,550,1,0,0, + 0,2776,2777,7,8,0,0,2777,2778,7,1,0,0,2778,2779,7,15,0,0,2779,2780, + 7,17,0,0,2780,2781,7,14,0,0,2781,2782,7,14,0,0,2782,552,1,0,0,0, + 2783,2784,7,8,0,0,2784,2785,7,1,0,0,2785,2786,7,15,0,0,2786,2787, + 7,10,0,0,2787,2788,7,16,0,0,2788,2789,7,15,0,0,2789,2790,7,17,0, + 0,2790,2791,7,14,0,0,2791,2792,7,14,0,0,2792,554,1,0,0,0,2793,2794, + 7,8,0,0,2794,2795,7,12,0,0,2795,2796,7,15,0,0,2796,2797,7,17,0,0, + 2797,2798,7,14,0,0,2798,2799,7,14,0,0,2799,556,1,0,0,0,2800,2801, + 7,15,0,0,2801,2802,7,17,0,0,2802,2803,7,14,0,0,2803,2804,7,14,0, + 0,2804,2805,7,8,0,0,2805,2806,7,12,0,0,2806,558,1,0,0,0,2807,2808, + 7,8,0,0,2808,2809,7,12,0,0,2809,560,1,0,0,0,2810,2811,7,16,0,0,2811, + 2812,7,23,0,0,2812,2813,7,18,0,0,2813,2814,7,2,0,0,2814,2815,7,10, + 0,0,2815,2816,7,12,0,0,2816,562,1,0,0,0,2817,2818,7,13,0,0,2818, + 2819,7,3,0,0,2819,2820,7,16,0,0,2820,2821,7,5,0,0,2821,2822,7,6, + 0,0,2822,564,1,0,0,0,2823,2824,7,13,0,0,2824,2825,7,3,0,0,2825,2826, + 7,16,0,0,2826,2827,7,5,0,0,2827,2828,7,6,0,0,2828,2829,5,95,0,0, + 2829,2830,7,18,0,0,2830,2831,7,6,0,0,2831,2832,7,4,0,0,2832,2833, + 7,3,0,0,2833,2834,7,1,0,0,2834,2835,7,2,0,0,2835,566,1,0,0,0,2836, + 2837,7,13,0,0,2837,2838,7,3,0,0,2838,2839,7,16,0,0,2839,2840,7,5, + 0,0,2840,2841,7,6,0,0,2841,2842,5,95,0,0,2842,2843,7,18,0,0,2843, + 2844,7,6,0,0,2844,2845,7,4,0,0,2845,2846,7,3,0,0,2846,2847,7,1,0, + 0,2847,2848,7,2,0,0,2848,2849,5,95,0,0,2849,2850,7,18,0,0,2850,2851, + 7,4,0,0,2851,2852,7,2,0,0,2852,2853,7,12,0,0,2853,2854,7,8,0,0,2854, + 2855,7,21,0,0,2855,568,1,0,0,0,2856,2857,7,13,0,0,2857,2858,7,3, + 0,0,2858,2859,7,16,0,0,2859,2860,7,5,0,0,2860,2861,7,6,0,0,2861, + 2862,5,95,0,0,2862,2863,7,9,0,0,2863,2864,7,10,0,0,2864,2865,7,10, + 0,0,2865,2866,7,14,0,0,2866,2867,5,95,0,0,2867,2868,7,18,0,0,2868, + 2869,7,4,0,0,2869,2870,7,2,0,0,2870,2871,7,12,0,0,2871,2872,7,8, + 0,0,2872,2873,7,21,0,0,2873,570,1,0,0,0,2874,2875,7,1,0,0,2875,2876, + 7,8,0,0,2876,2877,7,13,0,0,2877,2878,7,18,0,0,2878,2879,7,14,0,0, + 2879,2880,7,2,0,0,2880,2881,5,95,0,0,2881,2882,7,25,0,0,2882,2883, + 7,17,0,0,2883,2884,7,2,0,0,2884,2885,7,4,0,0,2885,2886,7,23,0,0, + 2886,2887,5,95,0,0,2887,2888,7,1,0,0,2888,2889,7,16,0,0,2889,2890, + 7,4,0,0,2890,2891,7,8,0,0,2891,2892,7,15,0,0,2892,2893,7,20,0,0, + 2893,572,1,0,0,0,2894,2895,7,13,0,0,2895,2896,7,17,0,0,2896,2897, + 7,14,0,0,2897,2898,7,16,0,0,2898,2899,7,8,0,0,2899,2900,5,95,0,0, + 2900,2901,7,13,0,0,2901,2902,7,3,0,0,2902,2903,7,16,0,0,2903,2904, + 7,5,0,0,2904,2905,7,6,0,0,2905,574,1,0,0,0,2906,2907,7,25,0,0,2907, + 2908,7,17,0,0,2908,2909,7,2,0,0,2909,2910,7,4,0,0,2910,2911,7,23, + 0,0,2911,2912,5,95,0,0,2912,2913,7,1,0,0,2913,2914,7,16,0,0,2914, + 2915,7,4,0,0,2915,2916,7,8,0,0,2916,2917,7,15,0,0,2917,2918,7,20, + 0,0,2918,576,1,0,0,0,2919,2920,7,3,0,0,2920,2921,7,14,0,0,2921,2922, + 7,14,0,0,2922,2923,7,10,0,0,2923,2924,7,11,0,0,2924,2925,5,95,0, + 0,2925,2926,7,14,0,0,2926,2927,7,2,0,0,2927,2928,7,3,0,0,2928,2929, + 7,7,0,0,2929,2930,7,8,0,0,2930,2931,7,15,0,0,2931,2932,7,20,0,0, + 2932,2933,5,95,0,0,2933,2934,7,11,0,0,2934,2935,7,8,0,0,2935,2936, + 7,14,0,0,2936,2937,7,7,0,0,2937,2938,7,5,0,0,2938,2939,7,3,0,0,2939, + 2940,7,4,0,0,2940,2941,7,7,0,0,2941,578,1,0,0,0,2942,2943,7,3,0, + 0,2943,2944,7,15,0,0,2944,2945,7,3,0,0,2945,2946,7,14,0,0,2946,2947, + 7,23,0,0,2947,2948,7,24,0,0,2948,2949,7,2,0,0,2949,2950,5,95,0,0, + 2950,2951,7,11,0,0,2951,2952,7,8,0,0,2952,2953,7,14,0,0,2953,2954, + 7,7,0,0,2954,2955,7,5,0,0,2955,2956,7,3,0,0,2956,2957,7,4,0,0,2957, + 2958,7,7,0,0,2958,580,1,0,0,0,2959,2960,7,3,0,0,2960,2961,7,15,0, + 0,2961,2962,7,3,0,0,2962,2963,7,14,0,0,2963,2964,7,23,0,0,2964,2965, + 7,24,0,0,2965,2966,7,2,0,0,2966,2967,7,4,0,0,2967,582,1,0,0,0,2968, + 2969,7,3,0,0,2969,2970,7,17,0,0,2970,2971,7,16,0,0,2971,2972,7,10, + 0,0,2972,2973,5,95,0,0,2973,2974,7,20,0,0,2974,2975,7,2,0,0,2975, + 2976,7,15,0,0,2976,2977,7,2,0,0,2977,2978,7,4,0,0,2978,2979,7,3, + 0,0,2979,2980,7,16,0,0,2980,2981,7,2,0,0,2981,2982,5,95,0,0,2982, + 2983,7,1,0,0,2983,2984,7,23,0,0,2984,2985,7,15,0,0,2985,2986,7,10, + 0,0,2986,2987,7,15,0,0,2987,2988,7,23,0,0,2988,2989,7,13,0,0,2989, + 2990,7,1,0,0,2990,2991,5,95,0,0,2991,2992,7,18,0,0,2992,2993,7,6, + 0,0,2993,2994,7,4,0,0,2994,2995,7,3,0,0,2995,2996,7,1,0,0,2996,2997, + 7,2,0,0,2997,2998,5,95,0,0,2998,2999,7,25,0,0,2999,3000,7,17,0,0, + 3000,3001,7,2,0,0,3001,3002,7,4,0,0,3002,3003,7,23,0,0,3003,584, + 1,0,0,0,3004,3005,7,9,0,0,3005,3006,7,10,0,0,3006,3007,7,10,0,0, + 3007,3008,7,1,0,0,3008,3009,7,16,0,0,3009,586,1,0,0,0,3010,3011, + 7,5,0,0,3011,3012,7,17,0,0,3012,3013,7,16,0,0,3013,3014,7,10,0,0, + 3014,3015,7,12,0,0,3015,3016,7,12,0,0,3016,3017,5,95,0,0,3017,3018, + 7,12,0,0,3018,3019,7,4,0,0,3019,3020,7,2,0,0,3020,3021,7,25,0,0, + 3021,3022,7,17,0,0,3022,3023,7,2,0,0,3023,3024,7,15,0,0,3024,3025, + 7,5,0,0,3025,3026,7,23,0,0,3026,588,1,0,0,0,3027,3028,7,7,0,0,3028, + 3029,7,2,0,0,3029,3030,7,12,0,0,3030,3031,7,3,0,0,3031,3032,7,17, + 0,0,3032,3033,7,14,0,0,3033,3034,7,16,0,0,3034,3035,5,95,0,0,3035, + 3036,7,12,0,0,3036,3037,7,8,0,0,3037,3038,7,2,0,0,3038,3039,7,14, + 0,0,3039,3040,7,7,0,0,3040,590,1,0,0,0,3041,3042,7,7,0,0,3042,3043, + 7,2,0,0,3043,3044,7,12,0,0,3044,3045,7,3,0,0,3045,3046,7,17,0,0, + 3046,3047,7,14,0,0,3047,3048,7,16,0,0,3048,3049,5,95,0,0,3049,3050, + 7,10,0,0,3050,3051,7,18,0,0,3051,3052,7,2,0,0,3052,3053,7,4,0,0, + 3053,3054,7,3,0,0,3054,3055,7,16,0,0,3055,3056,7,10,0,0,3056,3057, + 7,4,0,0,3057,592,1,0,0,0,3058,3059,7,2,0,0,3059,3060,7,15,0,0,3060, + 3061,7,3,0,0,3061,3062,7,9,0,0,3062,3063,7,14,0,0,3063,3064,7,2, + 0,0,3064,3065,5,95,0,0,3065,3066,7,18,0,0,3066,3067,7,10,0,0,3067, + 3068,7,1,0,0,3068,3069,7,8,0,0,3069,3070,7,16,0,0,3070,3071,7,8, + 0,0,3071,3072,7,10,0,0,3072,3073,7,15,0,0,3073,3074,5,95,0,0,3074, + 3075,7,8,0,0,3075,3076,7,15,0,0,3076,3077,7,5,0,0,3077,3078,7,4, + 0,0,3078,3079,7,2,0,0,3079,3080,7,13,0,0,3080,3081,7,2,0,0,3081, + 3082,7,15,0,0,3082,3083,7,16,0,0,3083,3084,7,1,0,0,3084,594,1,0, + 0,0,3085,3086,7,2,0,0,3086,3087,7,1,0,0,3087,3088,7,5,0,0,3088,3089, + 7,3,0,0,3089,3090,7,18,0,0,3090,3091,7,2,0,0,3091,596,1,0,0,0,3092, + 3093,7,12,0,0,3093,3094,7,14,0,0,3094,3095,7,3,0,0,3095,3096,7,20, + 0,0,3096,3097,7,1,0,0,3097,598,1,0,0,0,3098,3099,7,12,0,0,3099,3100, + 7,17,0,0,3100,3101,7,24,0,0,3101,3102,7,24,0,0,3102,3103,7,23,0, + 0,3103,3104,5,95,0,0,3104,3105,7,13,0,0,3105,3106,7,3,0,0,3106,3107, + 7,21,0,0,3107,3108,5,95,0,0,3108,3109,7,2,0,0,3109,3110,7,21,0,0, + 3110,3111,7,18,0,0,3111,3112,7,3,0,0,3112,3113,7,15,0,0,3113,3114, + 7,1,0,0,3114,3115,7,8,0,0,3115,3116,7,10,0,0,3116,3117,7,15,0,0, + 3117,3118,7,1,0,0,3118,600,1,0,0,0,3119,3120,7,12,0,0,3120,3121, + 7,17,0,0,3121,3122,7,24,0,0,3122,3123,7,24,0,0,3123,3124,7,23,0, + 0,3124,3125,5,95,0,0,3125,3126,7,18,0,0,3126,3127,7,4,0,0,3127,3128, + 7,2,0,0,3128,3129,7,12,0,0,3129,3130,7,8,0,0,3130,3131,7,21,0,0, + 3131,3132,5,95,0,0,3132,3133,7,14,0,0,3133,3134,7,2,0,0,3134,3135, + 7,15,0,0,3135,3136,7,20,0,0,3136,3137,7,16,0,0,3137,3138,7,6,0,0, + 3138,602,1,0,0,0,3139,3140,7,12,0,0,3140,3141,7,17,0,0,3141,3142, + 7,24,0,0,3142,3143,7,24,0,0,3143,3144,7,23,0,0,3144,3145,5,95,0, + 0,3145,3146,7,16,0,0,3146,3147,7,4,0,0,3147,3148,7,3,0,0,3148,3149, + 7,15,0,0,3149,3150,7,1,0,0,3150,3151,7,18,0,0,3151,3152,7,10,0,0, + 3152,3153,7,1,0,0,3153,3154,7,8,0,0,3154,3155,7,16,0,0,3155,3156, + 7,8,0,0,3156,3157,7,10,0,0,3157,3158,7,15,0,0,3158,3159,7,1,0,0, + 3159,604,1,0,0,0,3160,3161,7,12,0,0,3161,3162,7,17,0,0,3162,3163, + 7,24,0,0,3163,3164,7,24,0,0,3164,3165,7,23,0,0,3165,3166,5,95,0, + 0,3166,3167,7,4,0,0,3167,3168,7,2,0,0,3168,3169,7,11,0,0,3169,3170, + 7,4,0,0,3170,3171,7,8,0,0,3171,3172,7,16,0,0,3172,3173,7,2,0,0,3173, + 606,1,0,0,0,3174,3175,7,12,0,0,3175,3176,7,17,0,0,3176,3177,7,24, + 0,0,3177,3178,7,24,0,0,3178,3179,7,8,0,0,3179,3180,7,15,0,0,3180, + 3181,7,2,0,0,3181,3182,7,1,0,0,3182,3183,7,1,0,0,3183,608,1,0,0, + 0,3184,3185,7,14,0,0,3185,3186,7,2,0,0,3186,3187,7,15,0,0,3187,3188, + 7,8,0,0,3188,3189,7,2,0,0,3189,3190,7,15,0,0,3190,3191,7,16,0,0, + 3191,610,1,0,0,0,3192,3193,7,14,0,0,3193,3194,7,10,0,0,3194,3195, + 7,11,0,0,3195,3196,5,95,0,0,3196,3197,7,12,0,0,3197,3198,7,4,0,0, + 3198,3199,7,2,0,0,3199,3200,7,25,0,0,3200,3201,5,95,0,0,3201,3202, + 7,10,0,0,3202,3203,7,18,0,0,3203,3204,7,2,0,0,3204,3205,7,4,0,0, + 3205,3206,7,3,0,0,3206,3207,7,16,0,0,3207,3208,7,10,0,0,3208,3209, + 7,4,0,0,3209,612,1,0,0,0,3210,3211,7,13,0,0,3211,3212,7,3,0,0,3212, + 3213,7,21,0,0,3213,3214,5,95,0,0,3214,3215,7,7,0,0,3215,3216,7,2, + 0,0,3216,3217,7,16,0,0,3217,3218,7,2,0,0,3218,3219,7,4,0,0,3219, + 3220,7,13,0,0,3220,3221,7,8,0,0,3221,3222,7,15,0,0,3222,3223,7,8, + 0,0,3223,3224,7,24,0,0,3224,3225,7,2,0,0,3225,3226,7,7,0,0,3226, + 3227,5,95,0,0,3227,3228,7,1,0,0,3228,3229,7,16,0,0,3229,3230,7,3, + 0,0,3230,3231,7,16,0,0,3231,3232,7,2,0,0,3232,3233,7,1,0,0,3233, + 614,1,0,0,0,3234,3235,7,13,0,0,3235,3236,7,3,0,0,3236,3237,7,21, + 0,0,3237,3238,5,95,0,0,3238,3239,7,2,0,0,3239,3240,7,21,0,0,3240, + 3241,7,18,0,0,3241,3242,7,3,0,0,3242,3243,7,15,0,0,3243,3244,7,1, + 0,0,3244,3245,7,8,0,0,3245,3246,7,10,0,0,3246,3247,7,15,0,0,3247, + 3248,7,1,0,0,3248,616,1,0,0,0,3249,3250,7,13,0,0,3250,3251,7,8,0, + 0,3251,3252,7,15,0,0,3252,3253,7,8,0,0,3253,3254,7,13,0,0,3254,3255, + 7,17,0,0,3255,3256,7,13,0,0,3256,3257,5,95,0,0,3257,3258,7,1,0,0, + 3258,3259,7,6,0,0,3259,3260,7,10,0,0,3260,3261,7,17,0,0,3261,3262, + 7,14,0,0,3262,3263,7,7,0,0,3263,3264,5,95,0,0,3264,3265,7,13,0,0, + 3265,3266,7,3,0,0,3266,3267,7,16,0,0,3267,3268,7,5,0,0,3268,3269, + 7,6,0,0,3269,618,1,0,0,0,3270,3271,7,10,0,0,3271,3272,7,18,0,0,3272, + 3273,7,2,0,0,3273,3274,7,4,0,0,3274,3275,7,3,0,0,3275,3276,7,16, + 0,0,3276,3277,7,10,0,0,3277,3278,7,4,0,0,3278,620,1,0,0,0,3279,3280, + 7,18,0,0,3280,3281,7,6,0,0,3281,3282,7,4,0,0,3282,3283,7,3,0,0,3283, + 3284,7,1,0,0,3284,3285,7,2,0,0,3285,3286,5,95,0,0,3286,3287,7,1, + 0,0,3287,3288,7,14,0,0,3288,3289,7,10,0,0,3289,3290,7,18,0,0,3290, + 622,1,0,0,0,3291,3292,7,18,0,0,3292,3293,7,4,0,0,3293,3294,7,2,0, + 0,3294,3295,7,12,0,0,3295,3296,7,8,0,0,3296,3297,7,21,0,0,3297,3298, + 5,95,0,0,3298,3299,7,14,0,0,3299,3300,7,2,0,0,3300,3301,7,15,0,0, + 3301,3302,7,20,0,0,3302,3303,7,16,0,0,3303,3304,7,6,0,0,3304,624, + 1,0,0,0,3305,3306,7,25,0,0,3306,3307,7,17,0,0,3307,3308,7,10,0,0, + 3308,3309,7,16,0,0,3309,3310,7,2,0,0,3310,3311,5,95,0,0,3311,3312, + 7,3,0,0,3312,3313,7,15,0,0,3313,3314,7,3,0,0,3314,3315,7,14,0,0, + 3315,3316,7,23,0,0,3316,3317,7,24,0,0,3317,3318,7,2,0,0,3318,3319, + 7,4,0,0,3319,626,1,0,0,0,3320,3321,7,25,0,0,3321,3322,7,17,0,0,3322, + 3323,7,10,0,0,3323,3324,7,16,0,0,3324,3325,7,2,0,0,3325,3326,5,95, + 0,0,3326,3327,7,12,0,0,3327,3328,7,8,0,0,3328,3329,7,2,0,0,3329, + 3330,7,14,0,0,3330,3331,7,7,0,0,3331,3332,5,95,0,0,3332,3333,7,1, + 0,0,3333,3334,7,17,0,0,3334,3335,7,12,0,0,3335,3336,7,12,0,0,3336, + 3337,7,8,0,0,3337,3338,7,21,0,0,3338,628,1,0,0,0,3339,3340,7,4,0, + 0,3340,3341,7,2,0,0,3341,3342,7,11,0,0,3342,3343,7,4,0,0,3343,3344, + 7,8,0,0,3344,3345,7,16,0,0,3345,3346,7,2,0,0,3346,630,1,0,0,0,3347, + 3348,7,1,0,0,3348,3349,7,14,0,0,3349,3350,7,10,0,0,3350,3351,7,18, + 0,0,3351,632,1,0,0,0,3352,3353,7,16,0,0,3353,3354,7,8,0,0,3354,3355, + 7,2,0,0,3355,3356,5,95,0,0,3356,3357,7,9,0,0,3357,3358,7,4,0,0,3358, + 3359,7,2,0,0,3359,3360,7,3,0,0,3360,3361,7,22,0,0,3361,3362,7,2, + 0,0,3362,3363,7,4,0,0,3363,634,1,0,0,0,3364,3365,7,16,0,0,3365,3366, + 7,23,0,0,3366,3367,7,18,0,0,3367,3368,7,2,0,0,3368,636,1,0,0,0,3369, + 3370,7,24,0,0,3370,3371,7,2,0,0,3371,3372,7,4,0,0,3372,3373,7,10, + 0,0,3373,3374,5,95,0,0,3374,3375,7,16,0,0,3375,3376,7,2,0,0,3376, + 3377,7,4,0,0,3377,3378,7,13,0,0,3378,3379,7,1,0,0,3379,3380,5,95, + 0,0,3380,3381,7,25,0,0,3381,3382,7,17,0,0,3382,3383,7,2,0,0,3383, + 3384,7,4,0,0,3384,3385,7,23,0,0,3385,638,1,0,0,0,3386,3387,7,1,0, + 0,3387,3388,7,18,0,0,3388,3389,7,3,0,0,3389,3390,7,15,0,0,3390,640, + 1,0,0,0,3391,3392,7,13,0,0,3392,3393,7,1,0,0,3393,642,1,0,0,0,3394, + 3395,7,1,0,0,3395,644,1,0,0,0,3396,3397,7,13,0,0,3397,646,1,0,0, + 0,3398,3399,7,6,0,0,3399,648,1,0,0,0,3400,3401,7,11,0,0,3401,650, + 1,0,0,0,3402,3403,7,25,0,0,3403,652,1,0,0,0,3404,3405,7,23,0,0,3405, + 654,1,0,0,0,3406,3407,3,665,332,0,3407,656,1,0,0,0,3408,3409,3,667, + 333,0,3409,658,1,0,0,0,3410,3412,3,677,338,0,3411,3410,1,0,0,0,3412, + 3413,1,0,0,0,3413,3411,1,0,0,0,3413,3414,1,0,0,0,3414,660,1,0,0, + 0,3415,3417,3,677,338,0,3416,3415,1,0,0,0,3417,3418,1,0,0,0,3418, + 3416,1,0,0,0,3418,3419,1,0,0,0,3419,3421,1,0,0,0,3420,3416,1,0,0, + 0,3420,3421,1,0,0,0,3421,3422,1,0,0,0,3422,3424,5,46,0,0,3423,3425, + 3,677,338,0,3424,3423,1,0,0,0,3425,3426,1,0,0,0,3426,3424,1,0,0, + 0,3426,3427,1,0,0,0,3427,662,1,0,0,0,3428,3430,7,26,0,0,3429,3431, + 7,27,0,0,3430,3429,1,0,0,0,3431,3432,1,0,0,0,3432,3430,1,0,0,0,3432, + 3433,1,0,0,0,3433,3435,1,0,0,0,3434,3428,1,0,0,0,3435,3436,1,0,0, + 0,3436,3434,1,0,0,0,3436,3437,1,0,0,0,3437,664,1,0,0,0,3438,3442, + 7,28,0,0,3439,3441,7,29,0,0,3440,3439,1,0,0,0,3441,3444,1,0,0,0, + 3442,3440,1,0,0,0,3442,3443,1,0,0,0,3443,666,1,0,0,0,3444,3442,1, + 0,0,0,3445,3447,7,30,0,0,3446,3445,1,0,0,0,3447,3448,1,0,0,0,3448, + 3449,1,0,0,0,3448,3446,1,0,0,0,3449,3453,1,0,0,0,3450,3452,7,29, + 0,0,3451,3450,1,0,0,0,3452,3455,1,0,0,0,3453,3451,1,0,0,0,3453,3454, + 1,0,0,0,3454,3456,1,0,0,0,3455,3453,1,0,0,0,3456,3457,3,247,123, + 0,3457,668,1,0,0,0,3458,3460,3,667,333,0,3459,3458,1,0,0,0,3459, + 3460,1,0,0,0,3460,3461,1,0,0,0,3461,3462,3,665,332,0,3462,3463,3, + 663,331,0,3463,670,1,0,0,0,3464,3472,5,34,0,0,3465,3466,5,92,0,0, + 3466,3471,9,0,0,0,3467,3468,5,34,0,0,3468,3471,5,34,0,0,3469,3471, + 8,31,0,0,3470,3465,1,0,0,0,3470,3467,1,0,0,0,3470,3469,1,0,0,0,3471, + 3474,1,0,0,0,3472,3470,1,0,0,0,3472,3473,1,0,0,0,3473,3475,1,0,0, + 0,3474,3472,1,0,0,0,3475,3476,5,34,0,0,3476,672,1,0,0,0,3477,3485, + 5,39,0,0,3478,3479,5,92,0,0,3479,3484,9,0,0,0,3480,3481,5,39,0,0, + 3481,3484,5,39,0,0,3482,3484,8,32,0,0,3483,3478,1,0,0,0,3483,3480, + 1,0,0,0,3483,3482,1,0,0,0,3484,3487,1,0,0,0,3485,3483,1,0,0,0,3485, + 3486,1,0,0,0,3486,3488,1,0,0,0,3487,3485,1,0,0,0,3488,3489,5,39, + 0,0,3489,674,1,0,0,0,3490,3498,5,96,0,0,3491,3492,5,92,0,0,3492, + 3497,9,0,0,0,3493,3494,5,96,0,0,3494,3497,5,96,0,0,3495,3497,8,33, + 0,0,3496,3491,1,0,0,0,3496,3493,1,0,0,0,3496,3495,1,0,0,0,3497,3500, + 1,0,0,0,3498,3496,1,0,0,0,3498,3499,1,0,0,0,3499,3501,1,0,0,0,3500, + 3498,1,0,0,0,3501,3502,5,96,0,0,3502,676,1,0,0,0,3503,3504,7,34, + 0,0,3504,678,1,0,0,0,3505,3506,9,0,0,0,3506,3507,1,0,0,0,3507,3508, + 6,339,1,0,3508,680,1,0,0,0,18,0,684,3413,3418,3420,3426,3432,3436, + 3442,3448,3453,3459,3470,3472,3483,3485,3496,3498,2,0,1,0,0,3,0 + ]; + + private static __ATN: antlr.ATN; + public static get _ATN(): antlr.ATN { + if (!OpenSearchPPLLexer.__ATN) { + OpenSearchPPLLexer.__ATN = new antlr.ATNDeserializer().deserialize(OpenSearchPPLLexer._serializedATN); + } + + return OpenSearchPPLLexer.__ATN; + } + + + private static readonly vocabulary = new antlr.Vocabulary(OpenSearchPPLLexer.literalNames, OpenSearchPPLLexer.symbolicNames, []); + + public override get vocabulary(): antlr.Vocabulary { + return OpenSearchPPLLexer.vocabulary; + } + + private static readonly decisionsToDFA = OpenSearchPPLLexer._ATN.decisionToState.map( (ds: antlr.DecisionState, index: number) => new antlr.DFA(ds, index) ); +} \ No newline at end of file diff --git a/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.interp b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.interp new file mode 100644 index 000000000000..03d97e71ca14 --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.interp @@ -0,0 +1,797 @@ +token literal names: +null +null +'SEARCH' +'DESCRIBE' +'SHOW' +'FROM' +'WHERE' +'FIELDS' +'RENAME' +'STATS' +'DEDUP' +'SORT' +'EVAL' +'HEAD' +'TOP' +'RARE' +'PARSE' +'METHOD' +'REGEX' +'PUNCT' +'GROK' +'PATTERN' +'PATTERNS' +'NEW_FIELD' +'KMEANS' +'AD' +'ML' +'AS' +'BY' +'SOURCE' +'INDEX' +'D' +'DESC' +'DATASOURCES' +'SORTBY' +'AUTO' +'STR' +'IP' +'NUM' +'KEEPEMPTY' +'CONSECUTIVE' +'DEDUP_SPLITVALUES' +'PARTITIONS' +'ALLNUM' +'DELIM' +'CENTROIDS' +'ITERATIONS' +'DISTANCE_TYPE' +'NUMBER_OF_TREES' +'SHINGLE_SIZE' +'SAMPLE_SIZE' +'OUTPUT_AFTER' +'TIME_DECAY' +'ANOMALY_RATE' +'CATEGORY_FIELD' +'TIME_FIELD' +'TIME_ZONE' +'TRAINING_DATA_SIZE' +'ANOMALY_SCORE_THRESHOLD' +'CASE' +'IN' +'NOT' +'OR' +'AND' +'XOR' +'TRUE' +'FALSE' +'REGEXP' +'CONVERT_TZ' +'DATETIME' +'DAY' +'DAY_HOUR' +'DAY_MICROSECOND' +'DAY_MINUTE' +'DAY_OF_YEAR' +'DAY_SECOND' +'HOUR' +'HOUR_MICROSECOND' +'HOUR_MINUTE' +'HOUR_OF_DAY' +'HOUR_SECOND' +'INTERVAL' +'MICROSECOND' +'MILLISECOND' +'MINUTE' +'MINUTE_MICROSECOND' +'MINUTE_OF_DAY' +'MINUTE_OF_HOUR' +'MINUTE_SECOND' +'MONTH' +'MONTH_OF_YEAR' +'QUARTER' +'SECOND' +'SECOND_MICROSECOND' +'SECOND_OF_MINUTE' +'WEEK' +'WEEK_OF_YEAR' +'YEAR' +'YEAR_MONTH' +'DATAMODEL' +'LOOKUP' +'SAVEDSEARCH' +'INT' +'INTEGER' +'DOUBLE' +'LONG' +'FLOAT' +'STRING' +'BOOLEAN' +'|' +',' +'.' +'=' +'>' +'<' +null +null +null +'+' +'-' +'*' +'/' +'%' +'!' +':' +'(' +')' +'[' +']' +'\'' +'"' +'`' +'~' +'&' +'^' +'AVG' +'COUNT' +'DISTINCT_COUNT' +'ESTDC' +'ESTDC_ERROR' +'MAX' +'MEAN' +'MEDIAN' +'MIN' +'MODE' +'RANGE' +'STDEV' +'STDEVP' +'SUM' +'SUMSQ' +'VAR_SAMP' +'VAR_POP' +'STDDEV_SAMP' +'STDDEV_POP' +'PERCENTILE' +'TAKE' +'FIRST' +'LAST' +'LIST' +'VALUES' +'EARLIEST' +'EARLIEST_TIME' +'LATEST' +'LATEST_TIME' +'PER_DAY' +'PER_HOUR' +'PER_MINUTE' +'PER_SECOND' +'RATE' +'SPARKLINE' +'C' +'DC' +'ABS' +'CBRT' +'CEIL' +'CEILING' +'CONV' +'CRC32' +'E' +'EXP' +'FLOOR' +'LN' +'LOG' +'LOG10' +'LOG2' +'MOD' +'PI' +'POSITION' +'POW' +'POWER' +'RAND' +'ROUND' +'SIGN' +'SQRT' +'TRUNCATE' +'ACOS' +'ASIN' +'ATAN' +'ATAN2' +'COS' +'COT' +'DEGREES' +'RADIANS' +'SIN' +'TAN' +'ADDDATE' +'ADDTIME' +'CURDATE' +'CURRENT_DATE' +'CURRENT_TIME' +'CURRENT_TIMESTAMP' +'CURTIME' +'DATE' +'DATEDIFF' +'DATE_ADD' +'DATE_FORMAT' +'DATE_SUB' +'DAYNAME' +'DAYOFMONTH' +'DAYOFWEEK' +'DAYOFYEAR' +'DAY_OF_MONTH' +'DAY_OF_WEEK' +'EXTRACT' +'FROM_DAYS' +'FROM_UNIXTIME' +'GET_FORMAT' +'LAST_DAY' +'LOCALTIME' +'LOCALTIMESTAMP' +'MAKEDATE' +'MAKETIME' +'MONTHNAME' +'NOW' +'PERIOD_ADD' +'PERIOD_DIFF' +'SEC_TO_TIME' +'STR_TO_DATE' +'SUBDATE' +'SUBTIME' +'SYSDATE' +'TIME' +'TIMEDIFF' +'TIMESTAMP' +'TIMESTAMPADD' +'TIMESTAMPDIFF' +'TIME_FORMAT' +'TIME_TO_SEC' +'TO_DAYS' +'TO_SECONDS' +'UNIX_TIMESTAMP' +'UTC_DATE' +'UTC_TIME' +'UTC_TIMESTAMP' +'WEEKDAY' +'YEARWEEK' +'SUBSTR' +'SUBSTRING' +'LTRIM' +'RTRIM' +'TRIM' +'TO' +'LOWER' +'UPPER' +'CONCAT' +'CONCAT_WS' +'LENGTH' +'STRCMP' +'RIGHT' +'LEFT' +'ASCII' +'LOCATE' +'REPLACE' +'REVERSE' +'CAST' +'LIKE' +'ISNULL' +'ISNOTNULL' +'IFNULL' +'NULLIF' +'IF' +'TYPEOF' +'MATCH' +'MATCH_PHRASE' +'MATCH_PHRASE_PREFIX' +'MATCH_BOOL_PREFIX' +'SIMPLE_QUERY_STRING' +'MULTI_MATCH' +'QUERY_STRING' +'ALLOW_LEADING_WILDCARD' +'ANALYZE_WILDCARD' +'ANALYZER' +'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY' +'BOOST' +'CUTOFF_FREQUENCY' +'DEFAULT_FIELD' +'DEFAULT_OPERATOR' +'ENABLE_POSITION_INCREMENTS' +'ESCAPE' +'FLAGS' +'FUZZY_MAX_EXPANSIONS' +'FUZZY_PREFIX_LENGTH' +'FUZZY_TRANSPOSITIONS' +'FUZZY_REWRITE' +'FUZZINESS' +'LENIENT' +'LOW_FREQ_OPERATOR' +'MAX_DETERMINIZED_STATES' +'MAX_EXPANSIONS' +'MINIMUM_SHOULD_MATCH' +'OPERATOR' +'PHRASE_SLOP' +'PREFIX_LENGTH' +'QUOTE_ANALYZER' +'QUOTE_FIELD_SUFFIX' +'REWRITE' +'SLOP' +'TIE_BREAKER' +'TYPE' +'ZERO_TERMS_QUERY' +'SPAN' +'MS' +'S' +'M' +'H' +'W' +'Q' +'Y' +null +null +null +null +null +null +null +null +null + +token symbolic names: +null +SPACE +SEARCH +DESCRIBE +SHOW +FROM +WHERE +FIELDS +RENAME +STATS +DEDUP +SORT +EVAL +HEAD +TOP +RARE +PARSE +METHOD +REGEX +PUNCT +GROK +PATTERN +PATTERNS +NEW_FIELD +KMEANS +AD +ML +AS +BY +SOURCE +INDEX +D +DESC +DATASOURCES +SORTBY +AUTO +STR +IP +NUM +KEEPEMPTY +CONSECUTIVE +DEDUP_SPLITVALUES +PARTITIONS +ALLNUM +DELIM +CENTROIDS +ITERATIONS +DISTANCE_TYPE +NUMBER_OF_TREES +SHINGLE_SIZE +SAMPLE_SIZE +OUTPUT_AFTER +TIME_DECAY +ANOMALY_RATE +CATEGORY_FIELD +TIME_FIELD +TIME_ZONE +TRAINING_DATA_SIZE +ANOMALY_SCORE_THRESHOLD +CASE +IN +NOT +OR +AND +XOR +TRUE +FALSE +REGEXP +CONVERT_TZ +DATETIME +DAY +DAY_HOUR +DAY_MICROSECOND +DAY_MINUTE +DAY_OF_YEAR +DAY_SECOND +HOUR +HOUR_MICROSECOND +HOUR_MINUTE +HOUR_OF_DAY +HOUR_SECOND +INTERVAL +MICROSECOND +MILLISECOND +MINUTE +MINUTE_MICROSECOND +MINUTE_OF_DAY +MINUTE_OF_HOUR +MINUTE_SECOND +MONTH +MONTH_OF_YEAR +QUARTER +SECOND +SECOND_MICROSECOND +SECOND_OF_MINUTE +WEEK +WEEK_OF_YEAR +YEAR +YEAR_MONTH +DATAMODEL +LOOKUP +SAVEDSEARCH +INT +INTEGER +DOUBLE +LONG +FLOAT +STRING +BOOLEAN +PIPE +COMMA +DOT +EQUAL +GREATER +LESS +NOT_GREATER +NOT_LESS +NOT_EQUAL +PLUS +MINUS +STAR +DIVIDE +MODULE +EXCLAMATION_SYMBOL +COLON +LT_PRTHS +RT_PRTHS +LT_SQR_PRTHS +RT_SQR_PRTHS +SINGLE_QUOTE +DOUBLE_QUOTE +BACKTICK +BIT_NOT_OP +BIT_AND_OP +BIT_XOR_OP +AVG +COUNT +DISTINCT_COUNT +ESTDC +ESTDC_ERROR +MAX +MEAN +MEDIAN +MIN +MODE +RANGE +STDEV +STDEVP +SUM +SUMSQ +VAR_SAMP +VAR_POP +STDDEV_SAMP +STDDEV_POP +PERCENTILE +TAKE +FIRST +LAST +LIST +VALUES +EARLIEST +EARLIEST_TIME +LATEST +LATEST_TIME +PER_DAY +PER_HOUR +PER_MINUTE +PER_SECOND +RATE +SPARKLINE +C +DC +ABS +CBRT +CEIL +CEILING +CONV +CRC32 +E +EXP +FLOOR +LN +LOG +LOG10 +LOG2 +MOD +PI +POSITION +POW +POWER +RAND +ROUND +SIGN +SQRT +TRUNCATE +ACOS +ASIN +ATAN +ATAN2 +COS +COT +DEGREES +RADIANS +SIN +TAN +ADDDATE +ADDTIME +CURDATE +CURRENT_DATE +CURRENT_TIME +CURRENT_TIMESTAMP +CURTIME +DATE +DATEDIFF +DATE_ADD +DATE_FORMAT +DATE_SUB +DAYNAME +DAYOFMONTH +DAYOFWEEK +DAYOFYEAR +DAY_OF_MONTH +DAY_OF_WEEK +EXTRACT +FROM_DAYS +FROM_UNIXTIME +GET_FORMAT +LAST_DAY +LOCALTIME +LOCALTIMESTAMP +MAKEDATE +MAKETIME +MONTHNAME +NOW +PERIOD_ADD +PERIOD_DIFF +SEC_TO_TIME +STR_TO_DATE +SUBDATE +SUBTIME +SYSDATE +TIME +TIMEDIFF +TIMESTAMP +TIMESTAMPADD +TIMESTAMPDIFF +TIME_FORMAT +TIME_TO_SEC +TO_DAYS +TO_SECONDS +UNIX_TIMESTAMP +UTC_DATE +UTC_TIME +UTC_TIMESTAMP +WEEKDAY +YEARWEEK +SUBSTR +SUBSTRING +LTRIM +RTRIM +TRIM +TO +LOWER +UPPER +CONCAT +CONCAT_WS +LENGTH +STRCMP +RIGHT +LEFT +ASCII +LOCATE +REPLACE +REVERSE +CAST +LIKE +ISNULL +ISNOTNULL +IFNULL +NULLIF +IF +TYPEOF +MATCH +MATCH_PHRASE +MATCH_PHRASE_PREFIX +MATCH_BOOL_PREFIX +SIMPLE_QUERY_STRING +MULTI_MATCH +QUERY_STRING +ALLOW_LEADING_WILDCARD +ANALYZE_WILDCARD +ANALYZER +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY +BOOST +CUTOFF_FREQUENCY +DEFAULT_FIELD +DEFAULT_OPERATOR +ENABLE_POSITION_INCREMENTS +ESCAPE +FLAGS +FUZZY_MAX_EXPANSIONS +FUZZY_PREFIX_LENGTH +FUZZY_TRANSPOSITIONS +FUZZY_REWRITE +FUZZINESS +LENIENT +LOW_FREQ_OPERATOR +MAX_DETERMINIZED_STATES +MAX_EXPANSIONS +MINIMUM_SHOULD_MATCH +OPERATOR +PHRASE_SLOP +PREFIX_LENGTH +QUOTE_ANALYZER +QUOTE_FIELD_SUFFIX +REWRITE +SLOP +TIE_BREAKER +TYPE +ZERO_TERMS_QUERY +SPAN +MS +S +M +H +W +Q +Y +ID +CLUSTER +INTEGER_LITERAL +DECIMAL_LITERAL +ID_DATE_SUFFIX +DQUOTA_STRING +SQUOTA_STRING +BQUOTA_STRING +ERROR_RECOGNITION + +rule names: +root +pplStatement +dmlStatement +queryStatement +pplCommands +commands +searchCommand +describeCommand +showDataSourcesCommand +whereCommand +fieldsCommand +renameCommand +statsCommand +dedupCommand +sortCommand +evalCommand +headCommand +topCommand +rareCommand +grokCommand +parseCommand +patternsCommand +patternsParameter +patternsMethod +kmeansCommand +kmeansParameter +adCommand +adParameter +mlCommand +mlArg +fromClause +tableSourceClause +renameClasue +byClause +statsByClause +bySpanClause +spanClause +sortbyClause +evalClause +statsAggTerm +statsFunction +statsFunctionName +takeAggFunction +percentileAggFunction +expression +logicalExpression +comparisonExpression +valueExpression +primaryExpression +positionFunction +booleanExpression +relevanceExpression +singleFieldRelevanceFunction +multiFieldRelevanceFunction +tableSource +tableFunction +fieldList +wcFieldList +sortField +sortFieldExpression +fieldExpression +wcFieldExpression +evalFunctionCall +dataTypeFunctionCall +booleanFunctionCall +convertedDataType +evalFunctionName +functionArgs +functionArg +relevanceArg +relevanceArgName +relevanceFieldAndWeight +relevanceFieldWeight +relevanceField +relevanceQuery +relevanceArgValue +mathematicalFunctionName +trigonometricFunctionName +dateTimeFunctionName +getFormatFunction +getFormatType +extractFunction +simpleDateTimePart +complexDateTimePart +datetimePart +timestampFunction +timestampFunctionName +conditionFunctionBase +systemFunctionName +textFunctionName +positionFunctionName +comparisonOperator +singleFieldRelevanceFunctionName +multiFieldRelevanceFunctionName +literalValue +intervalLiteral +stringLiteral +integerLiteral +decimalLiteral +booleanLiteral +datetimeLiteral +dateLiteral +timeLiteral +timestampLiteral +intervalUnit +timespanUnit +valueList +qualifiedName +tableQualifiedName +wcQualifiedName +ident +tableIdent +wildcard +keywordsCanBeId + + +atn: +[4, 1, 336, 1160, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 1, 0, 3, 0, 230, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 5, 3, 241, 8, 3, 10, 3, 12, 3, 244, 9, 3, 1, 4, 1, 4, 1, 4, 3, 4, 249, 8, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 267, 8, 5, 1, 6, 3, 6, 270, 8, 6, 1, 6, 1, 6, 3, 6, 274, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 280, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 285, 8, 6, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 3, 10, 298, 8, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 306, 8, 11, 10, 11, 12, 11, 309, 9, 11, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 315, 8, 12, 1, 12, 1, 12, 1, 12, 3, 12, 320, 8, 12, 1, 12, 1, 12, 1, 12, 3, 12, 325, 8, 12, 1, 12, 1, 12, 1, 12, 5, 12, 330, 8, 12, 10, 12, 12, 12, 333, 9, 12, 1, 12, 3, 12, 336, 8, 12, 1, 12, 1, 12, 1, 12, 3, 12, 341, 8, 12, 1, 13, 1, 13, 3, 13, 345, 8, 13, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 351, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 356, 8, 13, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 5, 15, 365, 8, 15, 10, 15, 12, 15, 368, 9, 15, 1, 16, 1, 16, 3, 16, 372, 8, 16, 1, 16, 1, 16, 3, 16, 376, 8, 16, 1, 17, 1, 17, 3, 17, 380, 8, 17, 1, 17, 1, 17, 3, 17, 384, 8, 17, 1, 18, 1, 18, 1, 18, 3, 18, 389, 8, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 5, 21, 401, 8, 21, 10, 21, 12, 21, 404, 9, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 414, 8, 22, 1, 23, 1, 23, 1, 24, 1, 24, 5, 24, 420, 8, 24, 10, 24, 12, 24, 423, 9, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 3, 25, 434, 8, 25, 1, 26, 1, 26, 5, 26, 438, 8, 26, 10, 26, 12, 26, 441, 9, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 3, 27, 479, 8, 27, 1, 28, 1, 28, 5, 28, 483, 8, 28, 10, 28, 12, 28, 486, 9, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 3, 30, 504, 8, 30, 1, 31, 1, 31, 1, 31, 5, 31, 509, 8, 31, 10, 31, 12, 31, 512, 9, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 3, 34, 530, 8, 34, 1, 35, 1, 35, 1, 35, 3, 35, 535, 8, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 543, 8, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 5, 37, 550, 8, 37, 10, 37, 12, 37, 553, 9, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 3, 39, 562, 8, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 3, 40, 579, 8, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 3, 42, 588, 8, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 3, 44, 603, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 3, 45, 611, 8, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 3, 45, 618, 8, 45, 1, 45, 1, 45, 1, 45, 1, 45, 5, 45, 624, 8, 45, 10, 45, 12, 45, 627, 9, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 3, 46, 637, 8, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 3, 47, 649, 8, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 5, 47, 657, 8, 47, 10, 47, 12, 47, 660, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 3, 48, 666, 8, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 3, 51, 679, 8, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 5, 52, 688, 8, 52, 10, 52, 12, 52, 691, 9, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 5, 53, 701, 8, 53, 10, 53, 12, 53, 704, 9, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 5, 53, 711, 8, 53, 10, 53, 12, 53, 714, 9, 53, 1, 53, 1, 53, 1, 54, 1, 54, 3, 54, 720, 8, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 5, 56, 730, 8, 56, 10, 56, 12, 56, 733, 9, 56, 1, 57, 1, 57, 1, 57, 5, 57, 738, 8, 57, 10, 57, 12, 57, 741, 9, 57, 1, 58, 3, 58, 744, 8, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 3, 59, 769, 8, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 802, 8, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 810, 8, 66, 1, 67, 1, 67, 1, 67, 5, 67, 815, 8, 67, 10, 67, 12, 67, 818, 9, 67, 3, 67, 820, 8, 67, 1, 68, 1, 68, 1, 68, 3, 68, 825, 8, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 3, 71, 843, 8, 71, 1, 72, 1, 72, 3, 72, 847, 8, 72, 1, 73, 1, 73, 3, 73, 851, 8, 73, 1, 74, 1, 74, 1, 75, 1, 75, 3, 75, 857, 8, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 3, 76, 882, 8, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 83, 1, 83, 1, 84, 1, 84, 3, 84, 910, 8, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 87, 1, 87, 1, 88, 1, 88, 1, 89, 1, 89, 1, 90, 1, 90, 1, 91, 1, 91, 1, 92, 1, 92, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 3, 94, 943, 8, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 97, 3, 97, 952, 8, 97, 1, 97, 1, 97, 1, 98, 3, 98, 957, 8, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 3, 100, 966, 8, 100, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 5, 106, 985, 8, 106, 10, 106, 12, 106, 988, 9, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 5, 107, 995, 8, 107, 10, 107, 12, 107, 998, 9, 107, 1, 108, 1, 108, 1, 108, 5, 108, 1003, 8, 108, 10, 108, 12, 108, 1006, 9, 108, 1, 109, 1, 109, 1, 109, 5, 109, 1011, 8, 109, 10, 109, 12, 109, 1014, 9, 109, 1, 110, 3, 110, 1017, 8, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 3, 110, 1026, 8, 110, 1, 111, 3, 111, 1029, 8, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 5, 112, 1036, 8, 112, 10, 112, 12, 112, 1039, 9, 112, 1, 112, 3, 112, 1042, 8, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 3, 112, 1056, 8, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 3, 113, 1158, 8, 113, 1, 113, 0, 2, 90, 94, 114, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 0, 21, 1, 0, 118, 119, 1, 0, 18, 19, 2, 0, 137, 137, 171, 171, 5, 0, 135, 136, 140, 140, 143, 143, 148, 148, 150, 153, 1, 0, 120, 122, 3, 0, 7, 7, 56, 56, 289, 319, 1, 0, 195, 204, 13, 0, 68, 70, 74, 74, 76, 76, 79, 79, 82, 82, 84, 84, 86, 87, 89, 92, 94, 97, 205, 222, 224, 225, 227, 243, 246, 255, 4, 0, 69, 69, 212, 212, 241, 241, 243, 243, 8, 0, 70, 70, 76, 76, 82, 82, 84, 84, 89, 89, 91, 92, 95, 95, 97, 97, 8, 0, 71, 73, 75, 75, 77, 78, 80, 80, 85, 85, 88, 88, 93, 93, 98, 98, 1, 0, 244, 245, 1, 0, 275, 280, 2, 0, 256, 260, 262, 273, 2, 0, 67, 67, 112, 117, 1, 0, 282, 285, 1, 0, 286, 288, 1, 0, 333, 334, 1, 0, 65, 66, 9, 0, 70, 73, 75, 78, 80, 80, 82, 82, 84, 85, 88, 89, 91, 93, 95, 95, 97, 98, 9, 0, 31, 31, 70, 70, 76, 76, 83, 84, 89, 89, 91, 92, 95, 95, 97, 97, 321, 327, 1318, 0, 229, 1, 0, 0, 0, 2, 233, 1, 0, 0, 0, 4, 235, 1, 0, 0, 0, 6, 237, 1, 0, 0, 0, 8, 248, 1, 0, 0, 0, 10, 266, 1, 0, 0, 0, 12, 284, 1, 0, 0, 0, 14, 286, 1, 0, 0, 0, 16, 289, 1, 0, 0, 0, 18, 292, 1, 0, 0, 0, 20, 295, 1, 0, 0, 0, 22, 301, 1, 0, 0, 0, 24, 310, 1, 0, 0, 0, 26, 342, 1, 0, 0, 0, 28, 357, 1, 0, 0, 0, 30, 360, 1, 0, 0, 0, 32, 369, 1, 0, 0, 0, 34, 377, 1, 0, 0, 0, 36, 385, 1, 0, 0, 0, 38, 390, 1, 0, 0, 0, 40, 394, 1, 0, 0, 0, 42, 398, 1, 0, 0, 0, 44, 413, 1, 0, 0, 0, 46, 415, 1, 0, 0, 0, 48, 417, 1, 0, 0, 0, 50, 433, 1, 0, 0, 0, 52, 435, 1, 0, 0, 0, 54, 478, 1, 0, 0, 0, 56, 480, 1, 0, 0, 0, 58, 487, 1, 0, 0, 0, 60, 503, 1, 0, 0, 0, 62, 505, 1, 0, 0, 0, 64, 513, 1, 0, 0, 0, 66, 517, 1, 0, 0, 0, 68, 529, 1, 0, 0, 0, 70, 531, 1, 0, 0, 0, 72, 536, 1, 0, 0, 0, 74, 546, 1, 0, 0, 0, 76, 554, 1, 0, 0, 0, 78, 558, 1, 0, 0, 0, 80, 578, 1, 0, 0, 0, 82, 580, 1, 0, 0, 0, 84, 582, 1, 0, 0, 0, 86, 591, 1, 0, 0, 0, 88, 602, 1, 0, 0, 0, 90, 610, 1, 0, 0, 0, 92, 636, 1, 0, 0, 0, 94, 648, 1, 0, 0, 0, 96, 665, 1, 0, 0, 0, 98, 667, 1, 0, 0, 0, 100, 674, 1, 0, 0, 0, 102, 678, 1, 0, 0, 0, 104, 680, 1, 0, 0, 0, 106, 694, 1, 0, 0, 0, 108, 719, 1, 0, 0, 0, 110, 721, 1, 0, 0, 0, 112, 726, 1, 0, 0, 0, 114, 734, 1, 0, 0, 0, 116, 743, 1, 0, 0, 0, 118, 768, 1, 0, 0, 0, 120, 770, 1, 0, 0, 0, 122, 772, 1, 0, 0, 0, 124, 774, 1, 0, 0, 0, 126, 779, 1, 0, 0, 0, 128, 786, 1, 0, 0, 0, 130, 801, 1, 0, 0, 0, 132, 809, 1, 0, 0, 0, 134, 819, 1, 0, 0, 0, 136, 824, 1, 0, 0, 0, 138, 828, 1, 0, 0, 0, 140, 832, 1, 0, 0, 0, 142, 842, 1, 0, 0, 0, 144, 846, 1, 0, 0, 0, 146, 850, 1, 0, 0, 0, 148, 852, 1, 0, 0, 0, 150, 856, 1, 0, 0, 0, 152, 881, 1, 0, 0, 0, 154, 883, 1, 0, 0, 0, 156, 885, 1, 0, 0, 0, 158, 887, 1, 0, 0, 0, 160, 894, 1, 0, 0, 0, 162, 896, 1, 0, 0, 0, 164, 903, 1, 0, 0, 0, 166, 905, 1, 0, 0, 0, 168, 909, 1, 0, 0, 0, 170, 911, 1, 0, 0, 0, 172, 920, 1, 0, 0, 0, 174, 922, 1, 0, 0, 0, 176, 924, 1, 0, 0, 0, 178, 926, 1, 0, 0, 0, 180, 928, 1, 0, 0, 0, 182, 930, 1, 0, 0, 0, 184, 932, 1, 0, 0, 0, 186, 934, 1, 0, 0, 0, 188, 942, 1, 0, 0, 0, 190, 944, 1, 0, 0, 0, 192, 948, 1, 0, 0, 0, 194, 951, 1, 0, 0, 0, 196, 956, 1, 0, 0, 0, 198, 960, 1, 0, 0, 0, 200, 965, 1, 0, 0, 0, 202, 967, 1, 0, 0, 0, 204, 970, 1, 0, 0, 0, 206, 973, 1, 0, 0, 0, 208, 976, 1, 0, 0, 0, 210, 978, 1, 0, 0, 0, 212, 980, 1, 0, 0, 0, 214, 991, 1, 0, 0, 0, 216, 999, 1, 0, 0, 0, 218, 1007, 1, 0, 0, 0, 220, 1025, 1, 0, 0, 0, 222, 1028, 1, 0, 0, 0, 224, 1055, 1, 0, 0, 0, 226, 1157, 1, 0, 0, 0, 228, 230, 3, 2, 1, 0, 229, 228, 1, 0, 0, 0, 229, 230, 1, 0, 0, 0, 230, 231, 1, 0, 0, 0, 231, 232, 5, 0, 0, 1, 232, 1, 1, 0, 0, 0, 233, 234, 3, 4, 2, 0, 234, 3, 1, 0, 0, 0, 235, 236, 3, 6, 3, 0, 236, 5, 1, 0, 0, 0, 237, 242, 3, 8, 4, 0, 238, 239, 5, 109, 0, 0, 239, 241, 3, 10, 5, 0, 240, 238, 1, 0, 0, 0, 241, 244, 1, 0, 0, 0, 242, 240, 1, 0, 0, 0, 242, 243, 1, 0, 0, 0, 243, 7, 1, 0, 0, 0, 244, 242, 1, 0, 0, 0, 245, 249, 3, 12, 6, 0, 246, 249, 3, 14, 7, 0, 247, 249, 3, 16, 8, 0, 248, 245, 1, 0, 0, 0, 248, 246, 1, 0, 0, 0, 248, 247, 1, 0, 0, 0, 249, 9, 1, 0, 0, 0, 250, 267, 3, 18, 9, 0, 251, 267, 3, 20, 10, 0, 252, 267, 3, 22, 11, 0, 253, 267, 3, 24, 12, 0, 254, 267, 3, 26, 13, 0, 255, 267, 3, 28, 14, 0, 256, 267, 3, 30, 15, 0, 257, 267, 3, 32, 16, 0, 258, 267, 3, 34, 17, 0, 259, 267, 3, 36, 18, 0, 260, 267, 3, 38, 19, 0, 261, 267, 3, 40, 20, 0, 262, 267, 3, 42, 21, 0, 263, 267, 3, 48, 24, 0, 264, 267, 3, 52, 26, 0, 265, 267, 3, 56, 28, 0, 266, 250, 1, 0, 0, 0, 266, 251, 1, 0, 0, 0, 266, 252, 1, 0, 0, 0, 266, 253, 1, 0, 0, 0, 266, 254, 1, 0, 0, 0, 266, 255, 1, 0, 0, 0, 266, 256, 1, 0, 0, 0, 266, 257, 1, 0, 0, 0, 266, 258, 1, 0, 0, 0, 266, 259, 1, 0, 0, 0, 266, 260, 1, 0, 0, 0, 266, 261, 1, 0, 0, 0, 266, 262, 1, 0, 0, 0, 266, 263, 1, 0, 0, 0, 266, 264, 1, 0, 0, 0, 266, 265, 1, 0, 0, 0, 267, 11, 1, 0, 0, 0, 268, 270, 5, 2, 0, 0, 269, 268, 1, 0, 0, 0, 269, 270, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, 271, 285, 3, 60, 30, 0, 272, 274, 5, 2, 0, 0, 273, 272, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 275, 1, 0, 0, 0, 275, 276, 3, 60, 30, 0, 276, 277, 3, 90, 45, 0, 277, 285, 1, 0, 0, 0, 278, 280, 5, 2, 0, 0, 279, 278, 1, 0, 0, 0, 279, 280, 1, 0, 0, 0, 280, 281, 1, 0, 0, 0, 281, 282, 3, 90, 45, 0, 282, 283, 3, 60, 30, 0, 283, 285, 1, 0, 0, 0, 284, 269, 1, 0, 0, 0, 284, 273, 1, 0, 0, 0, 284, 279, 1, 0, 0, 0, 285, 13, 1, 0, 0, 0, 286, 287, 5, 3, 0, 0, 287, 288, 3, 62, 31, 0, 288, 15, 1, 0, 0, 0, 289, 290, 5, 4, 0, 0, 290, 291, 5, 33, 0, 0, 291, 17, 1, 0, 0, 0, 292, 293, 5, 6, 0, 0, 293, 294, 3, 90, 45, 0, 294, 19, 1, 0, 0, 0, 295, 297, 5, 7, 0, 0, 296, 298, 7, 0, 0, 0, 297, 296, 1, 0, 0, 0, 297, 298, 1, 0, 0, 0, 298, 299, 1, 0, 0, 0, 299, 300, 3, 112, 56, 0, 300, 21, 1, 0, 0, 0, 301, 302, 5, 8, 0, 0, 302, 307, 3, 64, 32, 0, 303, 304, 5, 110, 0, 0, 304, 306, 3, 64, 32, 0, 305, 303, 1, 0, 0, 0, 306, 309, 1, 0, 0, 0, 307, 305, 1, 0, 0, 0, 307, 308, 1, 0, 0, 0, 308, 23, 1, 0, 0, 0, 309, 307, 1, 0, 0, 0, 310, 314, 5, 9, 0, 0, 311, 312, 5, 42, 0, 0, 312, 313, 5, 112, 0, 0, 313, 315, 3, 194, 97, 0, 314, 311, 1, 0, 0, 0, 314, 315, 1, 0, 0, 0, 315, 319, 1, 0, 0, 0, 316, 317, 5, 43, 0, 0, 317, 318, 5, 112, 0, 0, 318, 320, 3, 198, 99, 0, 319, 316, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 324, 1, 0, 0, 0, 321, 322, 5, 44, 0, 0, 322, 323, 5, 112, 0, 0, 323, 325, 3, 192, 96, 0, 324, 321, 1, 0, 0, 0, 324, 325, 1, 0, 0, 0, 325, 326, 1, 0, 0, 0, 326, 331, 3, 78, 39, 0, 327, 328, 5, 110, 0, 0, 328, 330, 3, 78, 39, 0, 329, 327, 1, 0, 0, 0, 330, 333, 1, 0, 0, 0, 331, 329, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 335, 1, 0, 0, 0, 333, 331, 1, 0, 0, 0, 334, 336, 3, 68, 34, 0, 335, 334, 1, 0, 0, 0, 335, 336, 1, 0, 0, 0, 336, 340, 1, 0, 0, 0, 337, 338, 5, 41, 0, 0, 338, 339, 5, 112, 0, 0, 339, 341, 3, 198, 99, 0, 340, 337, 1, 0, 0, 0, 340, 341, 1, 0, 0, 0, 341, 25, 1, 0, 0, 0, 342, 344, 5, 10, 0, 0, 343, 345, 3, 194, 97, 0, 344, 343, 1, 0, 0, 0, 344, 345, 1, 0, 0, 0, 345, 346, 1, 0, 0, 0, 346, 350, 3, 112, 56, 0, 347, 348, 5, 39, 0, 0, 348, 349, 5, 112, 0, 0, 349, 351, 3, 198, 99, 0, 350, 347, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 355, 1, 0, 0, 0, 352, 353, 5, 40, 0, 0, 353, 354, 5, 112, 0, 0, 354, 356, 3, 198, 99, 0, 355, 352, 1, 0, 0, 0, 355, 356, 1, 0, 0, 0, 356, 27, 1, 0, 0, 0, 357, 358, 5, 11, 0, 0, 358, 359, 3, 74, 37, 0, 359, 29, 1, 0, 0, 0, 360, 361, 5, 12, 0, 0, 361, 366, 3, 76, 38, 0, 362, 363, 5, 110, 0, 0, 363, 365, 3, 76, 38, 0, 364, 362, 1, 0, 0, 0, 365, 368, 1, 0, 0, 0, 366, 364, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 31, 1, 0, 0, 0, 368, 366, 1, 0, 0, 0, 369, 371, 5, 13, 0, 0, 370, 372, 3, 194, 97, 0, 371, 370, 1, 0, 0, 0, 371, 372, 1, 0, 0, 0, 372, 375, 1, 0, 0, 0, 373, 374, 5, 5, 0, 0, 374, 376, 3, 194, 97, 0, 375, 373, 1, 0, 0, 0, 375, 376, 1, 0, 0, 0, 376, 33, 1, 0, 0, 0, 377, 379, 5, 14, 0, 0, 378, 380, 3, 194, 97, 0, 379, 378, 1, 0, 0, 0, 379, 380, 1, 0, 0, 0, 380, 381, 1, 0, 0, 0, 381, 383, 3, 112, 56, 0, 382, 384, 3, 66, 33, 0, 383, 382, 1, 0, 0, 0, 383, 384, 1, 0, 0, 0, 384, 35, 1, 0, 0, 0, 385, 386, 5, 15, 0, 0, 386, 388, 3, 112, 56, 0, 387, 389, 3, 66, 33, 0, 388, 387, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 37, 1, 0, 0, 0, 390, 391, 5, 20, 0, 0, 391, 392, 3, 88, 44, 0, 392, 393, 3, 192, 96, 0, 393, 39, 1, 0, 0, 0, 394, 395, 5, 16, 0, 0, 395, 396, 3, 88, 44, 0, 396, 397, 3, 192, 96, 0, 397, 41, 1, 0, 0, 0, 398, 402, 5, 22, 0, 0, 399, 401, 3, 44, 22, 0, 400, 399, 1, 0, 0, 0, 401, 404, 1, 0, 0, 0, 402, 400, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 405, 1, 0, 0, 0, 404, 402, 1, 0, 0, 0, 405, 406, 3, 88, 44, 0, 406, 43, 1, 0, 0, 0, 407, 408, 5, 23, 0, 0, 408, 409, 5, 112, 0, 0, 409, 414, 3, 192, 96, 0, 410, 411, 5, 21, 0, 0, 411, 412, 5, 112, 0, 0, 412, 414, 3, 192, 96, 0, 413, 407, 1, 0, 0, 0, 413, 410, 1, 0, 0, 0, 414, 45, 1, 0, 0, 0, 415, 416, 7, 1, 0, 0, 416, 47, 1, 0, 0, 0, 417, 421, 5, 24, 0, 0, 418, 420, 3, 50, 25, 0, 419, 418, 1, 0, 0, 0, 420, 423, 1, 0, 0, 0, 421, 419, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 49, 1, 0, 0, 0, 423, 421, 1, 0, 0, 0, 424, 425, 5, 45, 0, 0, 425, 426, 5, 112, 0, 0, 426, 434, 3, 194, 97, 0, 427, 428, 5, 46, 0, 0, 428, 429, 5, 112, 0, 0, 429, 434, 3, 194, 97, 0, 430, 431, 5, 47, 0, 0, 431, 432, 5, 112, 0, 0, 432, 434, 3, 192, 96, 0, 433, 424, 1, 0, 0, 0, 433, 427, 1, 0, 0, 0, 433, 430, 1, 0, 0, 0, 434, 51, 1, 0, 0, 0, 435, 439, 5, 25, 0, 0, 436, 438, 3, 54, 27, 0, 437, 436, 1, 0, 0, 0, 438, 441, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 439, 440, 1, 0, 0, 0, 440, 53, 1, 0, 0, 0, 441, 439, 1, 0, 0, 0, 442, 443, 5, 48, 0, 0, 443, 444, 5, 112, 0, 0, 444, 479, 3, 194, 97, 0, 445, 446, 5, 49, 0, 0, 446, 447, 5, 112, 0, 0, 447, 479, 3, 194, 97, 0, 448, 449, 5, 50, 0, 0, 449, 450, 5, 112, 0, 0, 450, 479, 3, 194, 97, 0, 451, 452, 5, 51, 0, 0, 452, 453, 5, 112, 0, 0, 453, 479, 3, 194, 97, 0, 454, 455, 5, 52, 0, 0, 455, 456, 5, 112, 0, 0, 456, 479, 3, 196, 98, 0, 457, 458, 5, 53, 0, 0, 458, 459, 5, 112, 0, 0, 459, 479, 3, 196, 98, 0, 460, 461, 5, 54, 0, 0, 461, 462, 5, 112, 0, 0, 462, 479, 3, 192, 96, 0, 463, 464, 5, 55, 0, 0, 464, 465, 5, 112, 0, 0, 465, 479, 3, 192, 96, 0, 466, 467, 5, 215, 0, 0, 467, 468, 5, 112, 0, 0, 468, 479, 3, 192, 96, 0, 469, 470, 5, 56, 0, 0, 470, 471, 5, 112, 0, 0, 471, 479, 3, 192, 96, 0, 472, 473, 5, 57, 0, 0, 473, 474, 5, 112, 0, 0, 474, 479, 3, 194, 97, 0, 475, 476, 5, 58, 0, 0, 476, 477, 5, 112, 0, 0, 477, 479, 3, 196, 98, 0, 478, 442, 1, 0, 0, 0, 478, 445, 1, 0, 0, 0, 478, 448, 1, 0, 0, 0, 478, 451, 1, 0, 0, 0, 478, 454, 1, 0, 0, 0, 478, 457, 1, 0, 0, 0, 478, 460, 1, 0, 0, 0, 478, 463, 1, 0, 0, 0, 478, 466, 1, 0, 0, 0, 478, 469, 1, 0, 0, 0, 478, 472, 1, 0, 0, 0, 478, 475, 1, 0, 0, 0, 479, 55, 1, 0, 0, 0, 480, 484, 5, 26, 0, 0, 481, 483, 3, 58, 29, 0, 482, 481, 1, 0, 0, 0, 483, 486, 1, 0, 0, 0, 484, 482, 1, 0, 0, 0, 484, 485, 1, 0, 0, 0, 485, 57, 1, 0, 0, 0, 486, 484, 1, 0, 0, 0, 487, 488, 3, 220, 110, 0, 488, 489, 5, 112, 0, 0, 489, 490, 3, 188, 94, 0, 490, 59, 1, 0, 0, 0, 491, 492, 5, 29, 0, 0, 492, 493, 5, 112, 0, 0, 493, 504, 3, 62, 31, 0, 494, 495, 5, 30, 0, 0, 495, 496, 5, 112, 0, 0, 496, 504, 3, 62, 31, 0, 497, 498, 5, 29, 0, 0, 498, 499, 5, 112, 0, 0, 499, 504, 3, 110, 55, 0, 500, 501, 5, 30, 0, 0, 501, 502, 5, 112, 0, 0, 502, 504, 3, 110, 55, 0, 503, 491, 1, 0, 0, 0, 503, 494, 1, 0, 0, 0, 503, 497, 1, 0, 0, 0, 503, 500, 1, 0, 0, 0, 504, 61, 1, 0, 0, 0, 505, 510, 3, 108, 54, 0, 506, 507, 5, 110, 0, 0, 507, 509, 3, 108, 54, 0, 508, 506, 1, 0, 0, 0, 509, 512, 1, 0, 0, 0, 510, 508, 1, 0, 0, 0, 510, 511, 1, 0, 0, 0, 511, 63, 1, 0, 0, 0, 512, 510, 1, 0, 0, 0, 513, 514, 3, 122, 61, 0, 514, 515, 5, 27, 0, 0, 515, 516, 3, 122, 61, 0, 516, 65, 1, 0, 0, 0, 517, 518, 5, 28, 0, 0, 518, 519, 3, 112, 56, 0, 519, 67, 1, 0, 0, 0, 520, 521, 5, 28, 0, 0, 521, 530, 3, 112, 56, 0, 522, 523, 5, 28, 0, 0, 523, 530, 3, 70, 35, 0, 524, 525, 5, 28, 0, 0, 525, 526, 3, 70, 35, 0, 526, 527, 5, 110, 0, 0, 527, 528, 3, 112, 56, 0, 528, 530, 1, 0, 0, 0, 529, 520, 1, 0, 0, 0, 529, 522, 1, 0, 0, 0, 529, 524, 1, 0, 0, 0, 530, 69, 1, 0, 0, 0, 531, 534, 3, 72, 36, 0, 532, 533, 5, 27, 0, 0, 533, 535, 3, 214, 107, 0, 534, 532, 1, 0, 0, 0, 534, 535, 1, 0, 0, 0, 535, 71, 1, 0, 0, 0, 536, 537, 5, 320, 0, 0, 537, 538, 5, 125, 0, 0, 538, 539, 3, 120, 60, 0, 539, 540, 5, 110, 0, 0, 540, 542, 3, 188, 94, 0, 541, 543, 3, 210, 105, 0, 542, 541, 1, 0, 0, 0, 542, 543, 1, 0, 0, 0, 543, 544, 1, 0, 0, 0, 544, 545, 5, 126, 0, 0, 545, 73, 1, 0, 0, 0, 546, 551, 3, 116, 58, 0, 547, 548, 5, 110, 0, 0, 548, 550, 3, 116, 58, 0, 549, 547, 1, 0, 0, 0, 550, 553, 1, 0, 0, 0, 551, 549, 1, 0, 0, 0, 551, 552, 1, 0, 0, 0, 552, 75, 1, 0, 0, 0, 553, 551, 1, 0, 0, 0, 554, 555, 3, 120, 60, 0, 555, 556, 5, 112, 0, 0, 556, 557, 3, 88, 44, 0, 557, 77, 1, 0, 0, 0, 558, 561, 3, 80, 40, 0, 559, 560, 5, 27, 0, 0, 560, 562, 3, 122, 61, 0, 561, 559, 1, 0, 0, 0, 561, 562, 1, 0, 0, 0, 562, 79, 1, 0, 0, 0, 563, 564, 3, 82, 41, 0, 564, 565, 5, 125, 0, 0, 565, 566, 3, 94, 47, 0, 566, 567, 5, 126, 0, 0, 567, 579, 1, 0, 0, 0, 568, 569, 5, 136, 0, 0, 569, 570, 5, 125, 0, 0, 570, 579, 5, 126, 0, 0, 571, 572, 7, 2, 0, 0, 572, 573, 5, 125, 0, 0, 573, 574, 3, 94, 47, 0, 574, 575, 5, 126, 0, 0, 575, 579, 1, 0, 0, 0, 576, 579, 3, 86, 43, 0, 577, 579, 3, 84, 42, 0, 578, 563, 1, 0, 0, 0, 578, 568, 1, 0, 0, 0, 578, 571, 1, 0, 0, 0, 578, 576, 1, 0, 0, 0, 578, 577, 1, 0, 0, 0, 579, 81, 1, 0, 0, 0, 580, 581, 7, 3, 0, 0, 581, 83, 1, 0, 0, 0, 582, 583, 5, 155, 0, 0, 583, 584, 5, 125, 0, 0, 584, 587, 3, 120, 60, 0, 585, 586, 5, 110, 0, 0, 586, 588, 3, 194, 97, 0, 587, 585, 1, 0, 0, 0, 587, 588, 1, 0, 0, 0, 588, 589, 1, 0, 0, 0, 589, 590, 5, 126, 0, 0, 590, 85, 1, 0, 0, 0, 591, 592, 5, 154, 0, 0, 592, 593, 5, 114, 0, 0, 593, 594, 3, 194, 97, 0, 594, 595, 5, 113, 0, 0, 595, 596, 5, 125, 0, 0, 596, 597, 3, 120, 60, 0, 597, 598, 5, 126, 0, 0, 598, 87, 1, 0, 0, 0, 599, 603, 3, 90, 45, 0, 600, 603, 3, 92, 46, 0, 601, 603, 3, 94, 47, 0, 602, 599, 1, 0, 0, 0, 602, 600, 1, 0, 0, 0, 602, 601, 1, 0, 0, 0, 603, 89, 1, 0, 0, 0, 604, 605, 6, 45, -1, 0, 605, 611, 3, 92, 46, 0, 606, 607, 5, 61, 0, 0, 607, 611, 3, 90, 45, 6, 608, 611, 3, 100, 50, 0, 609, 611, 3, 102, 51, 0, 610, 604, 1, 0, 0, 0, 610, 606, 1, 0, 0, 0, 610, 608, 1, 0, 0, 0, 610, 609, 1, 0, 0, 0, 611, 625, 1, 0, 0, 0, 612, 613, 10, 5, 0, 0, 613, 614, 5, 62, 0, 0, 614, 624, 3, 90, 45, 6, 615, 617, 10, 4, 0, 0, 616, 618, 5, 63, 0, 0, 617, 616, 1, 0, 0, 0, 617, 618, 1, 0, 0, 0, 618, 619, 1, 0, 0, 0, 619, 624, 3, 90, 45, 5, 620, 621, 10, 3, 0, 0, 621, 622, 5, 64, 0, 0, 622, 624, 3, 90, 45, 4, 623, 612, 1, 0, 0, 0, 623, 615, 1, 0, 0, 0, 623, 620, 1, 0, 0, 0, 624, 627, 1, 0, 0, 0, 625, 623, 1, 0, 0, 0, 625, 626, 1, 0, 0, 0, 626, 91, 1, 0, 0, 0, 627, 625, 1, 0, 0, 0, 628, 629, 3, 94, 47, 0, 629, 630, 3, 182, 91, 0, 630, 631, 3, 94, 47, 0, 631, 637, 1, 0, 0, 0, 632, 633, 3, 94, 47, 0, 633, 634, 5, 60, 0, 0, 634, 635, 3, 212, 106, 0, 635, 637, 1, 0, 0, 0, 636, 628, 1, 0, 0, 0, 636, 632, 1, 0, 0, 0, 637, 93, 1, 0, 0, 0, 638, 639, 6, 47, -1, 0, 639, 649, 3, 96, 48, 0, 640, 649, 3, 98, 49, 0, 641, 649, 3, 162, 81, 0, 642, 649, 3, 158, 79, 0, 643, 649, 3, 170, 85, 0, 644, 645, 5, 125, 0, 0, 645, 646, 3, 94, 47, 0, 646, 647, 5, 126, 0, 0, 647, 649, 1, 0, 0, 0, 648, 638, 1, 0, 0, 0, 648, 640, 1, 0, 0, 0, 648, 641, 1, 0, 0, 0, 648, 642, 1, 0, 0, 0, 648, 643, 1, 0, 0, 0, 648, 644, 1, 0, 0, 0, 649, 658, 1, 0, 0, 0, 650, 651, 10, 8, 0, 0, 651, 652, 7, 4, 0, 0, 652, 657, 3, 94, 47, 9, 653, 654, 10, 7, 0, 0, 654, 655, 7, 0, 0, 0, 655, 657, 3, 94, 47, 8, 656, 650, 1, 0, 0, 0, 656, 653, 1, 0, 0, 0, 657, 660, 1, 0, 0, 0, 658, 656, 1, 0, 0, 0, 658, 659, 1, 0, 0, 0, 659, 95, 1, 0, 0, 0, 660, 658, 1, 0, 0, 0, 661, 666, 3, 124, 62, 0, 662, 666, 3, 126, 63, 0, 663, 666, 3, 120, 60, 0, 664, 666, 3, 188, 94, 0, 665, 661, 1, 0, 0, 0, 665, 662, 1, 0, 0, 0, 665, 663, 1, 0, 0, 0, 665, 664, 1, 0, 0, 0, 666, 97, 1, 0, 0, 0, 667, 668, 3, 180, 90, 0, 668, 669, 5, 125, 0, 0, 669, 670, 3, 136, 68, 0, 670, 671, 5, 60, 0, 0, 671, 672, 3, 136, 68, 0, 672, 673, 5, 126, 0, 0, 673, 99, 1, 0, 0, 0, 674, 675, 3, 128, 64, 0, 675, 101, 1, 0, 0, 0, 676, 679, 3, 104, 52, 0, 677, 679, 3, 106, 53, 0, 678, 676, 1, 0, 0, 0, 678, 677, 1, 0, 0, 0, 679, 103, 1, 0, 0, 0, 680, 681, 3, 184, 92, 0, 681, 682, 5, 125, 0, 0, 682, 683, 3, 146, 73, 0, 683, 684, 5, 110, 0, 0, 684, 689, 3, 148, 74, 0, 685, 686, 5, 110, 0, 0, 686, 688, 3, 138, 69, 0, 687, 685, 1, 0, 0, 0, 688, 691, 1, 0, 0, 0, 689, 687, 1, 0, 0, 0, 689, 690, 1, 0, 0, 0, 690, 692, 1, 0, 0, 0, 691, 689, 1, 0, 0, 0, 692, 693, 5, 126, 0, 0, 693, 105, 1, 0, 0, 0, 694, 695, 3, 186, 93, 0, 695, 696, 5, 125, 0, 0, 696, 697, 5, 127, 0, 0, 697, 702, 3, 142, 71, 0, 698, 699, 5, 110, 0, 0, 699, 701, 3, 142, 71, 0, 700, 698, 1, 0, 0, 0, 701, 704, 1, 0, 0, 0, 702, 700, 1, 0, 0, 0, 702, 703, 1, 0, 0, 0, 703, 705, 1, 0, 0, 0, 704, 702, 1, 0, 0, 0, 705, 706, 5, 128, 0, 0, 706, 707, 5, 110, 0, 0, 707, 712, 3, 148, 74, 0, 708, 709, 5, 110, 0, 0, 709, 711, 3, 138, 69, 0, 710, 708, 1, 0, 0, 0, 711, 714, 1, 0, 0, 0, 712, 710, 1, 0, 0, 0, 712, 713, 1, 0, 0, 0, 713, 715, 1, 0, 0, 0, 714, 712, 1, 0, 0, 0, 715, 716, 5, 126, 0, 0, 716, 107, 1, 0, 0, 0, 717, 720, 3, 216, 108, 0, 718, 720, 5, 332, 0, 0, 719, 717, 1, 0, 0, 0, 719, 718, 1, 0, 0, 0, 720, 109, 1, 0, 0, 0, 721, 722, 3, 214, 107, 0, 722, 723, 5, 125, 0, 0, 723, 724, 3, 134, 67, 0, 724, 725, 5, 126, 0, 0, 725, 111, 1, 0, 0, 0, 726, 731, 3, 120, 60, 0, 727, 728, 5, 110, 0, 0, 728, 730, 3, 120, 60, 0, 729, 727, 1, 0, 0, 0, 730, 733, 1, 0, 0, 0, 731, 729, 1, 0, 0, 0, 731, 732, 1, 0, 0, 0, 732, 113, 1, 0, 0, 0, 733, 731, 1, 0, 0, 0, 734, 739, 3, 122, 61, 0, 735, 736, 5, 110, 0, 0, 736, 738, 3, 122, 61, 0, 737, 735, 1, 0, 0, 0, 738, 741, 1, 0, 0, 0, 739, 737, 1, 0, 0, 0, 739, 740, 1, 0, 0, 0, 740, 115, 1, 0, 0, 0, 741, 739, 1, 0, 0, 0, 742, 744, 7, 0, 0, 0, 743, 742, 1, 0, 0, 0, 743, 744, 1, 0, 0, 0, 744, 745, 1, 0, 0, 0, 745, 746, 3, 118, 59, 0, 746, 117, 1, 0, 0, 0, 747, 769, 3, 120, 60, 0, 748, 749, 5, 35, 0, 0, 749, 750, 5, 125, 0, 0, 750, 751, 3, 120, 60, 0, 751, 752, 5, 126, 0, 0, 752, 769, 1, 0, 0, 0, 753, 754, 5, 36, 0, 0, 754, 755, 5, 125, 0, 0, 755, 756, 3, 120, 60, 0, 756, 757, 5, 126, 0, 0, 757, 769, 1, 0, 0, 0, 758, 759, 5, 37, 0, 0, 759, 760, 5, 125, 0, 0, 760, 761, 3, 120, 60, 0, 761, 762, 5, 126, 0, 0, 762, 769, 1, 0, 0, 0, 763, 764, 5, 38, 0, 0, 764, 765, 5, 125, 0, 0, 765, 766, 3, 120, 60, 0, 766, 767, 5, 126, 0, 0, 767, 769, 1, 0, 0, 0, 768, 747, 1, 0, 0, 0, 768, 748, 1, 0, 0, 0, 768, 753, 1, 0, 0, 0, 768, 758, 1, 0, 0, 0, 768, 763, 1, 0, 0, 0, 769, 119, 1, 0, 0, 0, 770, 771, 3, 214, 107, 0, 771, 121, 1, 0, 0, 0, 772, 773, 3, 218, 109, 0, 773, 123, 1, 0, 0, 0, 774, 775, 3, 132, 66, 0, 775, 776, 5, 125, 0, 0, 776, 777, 3, 134, 67, 0, 777, 778, 5, 126, 0, 0, 778, 125, 1, 0, 0, 0, 779, 780, 5, 274, 0, 0, 780, 781, 5, 125, 0, 0, 781, 782, 3, 88, 44, 0, 782, 783, 5, 27, 0, 0, 783, 784, 3, 130, 65, 0, 784, 785, 5, 126, 0, 0, 785, 127, 1, 0, 0, 0, 786, 787, 3, 174, 87, 0, 787, 788, 5, 125, 0, 0, 788, 789, 3, 134, 67, 0, 789, 790, 5, 126, 0, 0, 790, 129, 1, 0, 0, 0, 791, 802, 5, 212, 0, 0, 792, 802, 5, 241, 0, 0, 793, 802, 5, 243, 0, 0, 794, 802, 5, 102, 0, 0, 795, 802, 5, 103, 0, 0, 796, 802, 5, 104, 0, 0, 797, 802, 5, 105, 0, 0, 798, 802, 5, 106, 0, 0, 799, 802, 5, 107, 0, 0, 800, 802, 5, 108, 0, 0, 801, 791, 1, 0, 0, 0, 801, 792, 1, 0, 0, 0, 801, 793, 1, 0, 0, 0, 801, 794, 1, 0, 0, 0, 801, 795, 1, 0, 0, 0, 801, 796, 1, 0, 0, 0, 801, 797, 1, 0, 0, 0, 801, 798, 1, 0, 0, 0, 801, 799, 1, 0, 0, 0, 801, 800, 1, 0, 0, 0, 802, 131, 1, 0, 0, 0, 803, 810, 3, 152, 76, 0, 804, 810, 3, 156, 78, 0, 805, 810, 3, 178, 89, 0, 806, 810, 3, 174, 87, 0, 807, 810, 3, 176, 88, 0, 808, 810, 3, 180, 90, 0, 809, 803, 1, 0, 0, 0, 809, 804, 1, 0, 0, 0, 809, 805, 1, 0, 0, 0, 809, 806, 1, 0, 0, 0, 809, 807, 1, 0, 0, 0, 809, 808, 1, 0, 0, 0, 810, 133, 1, 0, 0, 0, 811, 816, 3, 136, 68, 0, 812, 813, 5, 110, 0, 0, 813, 815, 3, 136, 68, 0, 814, 812, 1, 0, 0, 0, 815, 818, 1, 0, 0, 0, 816, 814, 1, 0, 0, 0, 816, 817, 1, 0, 0, 0, 817, 820, 1, 0, 0, 0, 818, 816, 1, 0, 0, 0, 819, 811, 1, 0, 0, 0, 819, 820, 1, 0, 0, 0, 820, 135, 1, 0, 0, 0, 821, 822, 3, 220, 110, 0, 822, 823, 5, 112, 0, 0, 823, 825, 1, 0, 0, 0, 824, 821, 1, 0, 0, 0, 824, 825, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 827, 3, 94, 47, 0, 827, 137, 1, 0, 0, 0, 828, 829, 3, 140, 70, 0, 829, 830, 5, 112, 0, 0, 830, 831, 3, 150, 75, 0, 831, 139, 1, 0, 0, 0, 832, 833, 7, 5, 0, 0, 833, 141, 1, 0, 0, 0, 834, 843, 3, 146, 73, 0, 835, 836, 3, 146, 73, 0, 836, 837, 3, 144, 72, 0, 837, 843, 1, 0, 0, 0, 838, 839, 3, 146, 73, 0, 839, 840, 5, 134, 0, 0, 840, 841, 3, 144, 72, 0, 841, 843, 1, 0, 0, 0, 842, 834, 1, 0, 0, 0, 842, 835, 1, 0, 0, 0, 842, 838, 1, 0, 0, 0, 843, 143, 1, 0, 0, 0, 844, 847, 3, 194, 97, 0, 845, 847, 3, 196, 98, 0, 846, 844, 1, 0, 0, 0, 846, 845, 1, 0, 0, 0, 847, 145, 1, 0, 0, 0, 848, 851, 3, 214, 107, 0, 849, 851, 3, 192, 96, 0, 850, 848, 1, 0, 0, 0, 850, 849, 1, 0, 0, 0, 851, 147, 1, 0, 0, 0, 852, 853, 3, 150, 75, 0, 853, 149, 1, 0, 0, 0, 854, 857, 3, 214, 107, 0, 855, 857, 3, 188, 94, 0, 856, 854, 1, 0, 0, 0, 856, 855, 1, 0, 0, 0, 857, 151, 1, 0, 0, 0, 858, 882, 5, 172, 0, 0, 859, 882, 5, 173, 0, 0, 860, 882, 5, 174, 0, 0, 861, 882, 5, 175, 0, 0, 862, 882, 5, 176, 0, 0, 863, 882, 5, 177, 0, 0, 864, 882, 5, 178, 0, 0, 865, 882, 5, 179, 0, 0, 866, 882, 5, 180, 0, 0, 867, 882, 5, 181, 0, 0, 868, 882, 5, 182, 0, 0, 869, 882, 5, 183, 0, 0, 870, 882, 5, 184, 0, 0, 871, 882, 5, 185, 0, 0, 872, 882, 5, 186, 0, 0, 873, 882, 5, 188, 0, 0, 874, 882, 5, 189, 0, 0, 875, 882, 5, 190, 0, 0, 876, 882, 5, 191, 0, 0, 877, 882, 5, 192, 0, 0, 878, 882, 5, 193, 0, 0, 879, 882, 5, 194, 0, 0, 880, 882, 3, 154, 77, 0, 881, 858, 1, 0, 0, 0, 881, 859, 1, 0, 0, 0, 881, 860, 1, 0, 0, 0, 881, 861, 1, 0, 0, 0, 881, 862, 1, 0, 0, 0, 881, 863, 1, 0, 0, 0, 881, 864, 1, 0, 0, 0, 881, 865, 1, 0, 0, 0, 881, 866, 1, 0, 0, 0, 881, 867, 1, 0, 0, 0, 881, 868, 1, 0, 0, 0, 881, 869, 1, 0, 0, 0, 881, 870, 1, 0, 0, 0, 881, 871, 1, 0, 0, 0, 881, 872, 1, 0, 0, 0, 881, 873, 1, 0, 0, 0, 881, 874, 1, 0, 0, 0, 881, 875, 1, 0, 0, 0, 881, 876, 1, 0, 0, 0, 881, 877, 1, 0, 0, 0, 881, 878, 1, 0, 0, 0, 881, 879, 1, 0, 0, 0, 881, 880, 1, 0, 0, 0, 882, 153, 1, 0, 0, 0, 883, 884, 7, 6, 0, 0, 884, 155, 1, 0, 0, 0, 885, 886, 7, 7, 0, 0, 886, 157, 1, 0, 0, 0, 887, 888, 5, 226, 0, 0, 888, 889, 5, 125, 0, 0, 889, 890, 3, 160, 80, 0, 890, 891, 5, 110, 0, 0, 891, 892, 3, 136, 68, 0, 892, 893, 5, 126, 0, 0, 893, 159, 1, 0, 0, 0, 894, 895, 7, 8, 0, 0, 895, 161, 1, 0, 0, 0, 896, 897, 5, 223, 0, 0, 897, 898, 5, 125, 0, 0, 898, 899, 3, 168, 84, 0, 899, 900, 5, 5, 0, 0, 900, 901, 3, 136, 68, 0, 901, 902, 5, 126, 0, 0, 902, 163, 1, 0, 0, 0, 903, 904, 7, 9, 0, 0, 904, 165, 1, 0, 0, 0, 905, 906, 7, 10, 0, 0, 906, 167, 1, 0, 0, 0, 907, 910, 3, 164, 82, 0, 908, 910, 3, 166, 83, 0, 909, 907, 1, 0, 0, 0, 909, 908, 1, 0, 0, 0, 910, 169, 1, 0, 0, 0, 911, 912, 3, 172, 86, 0, 912, 913, 5, 125, 0, 0, 913, 914, 3, 164, 82, 0, 914, 915, 5, 110, 0, 0, 915, 916, 3, 136, 68, 0, 916, 917, 5, 110, 0, 0, 917, 918, 3, 136, 68, 0, 918, 919, 5, 126, 0, 0, 919, 171, 1, 0, 0, 0, 920, 921, 7, 11, 0, 0, 921, 173, 1, 0, 0, 0, 922, 923, 7, 12, 0, 0, 923, 175, 1, 0, 0, 0, 924, 925, 5, 281, 0, 0, 925, 177, 1, 0, 0, 0, 926, 927, 7, 13, 0, 0, 927, 179, 1, 0, 0, 0, 928, 929, 5, 187, 0, 0, 929, 181, 1, 0, 0, 0, 930, 931, 7, 14, 0, 0, 931, 183, 1, 0, 0, 0, 932, 933, 7, 15, 0, 0, 933, 185, 1, 0, 0, 0, 934, 935, 7, 16, 0, 0, 935, 187, 1, 0, 0, 0, 936, 943, 3, 190, 95, 0, 937, 943, 3, 192, 96, 0, 938, 943, 3, 194, 97, 0, 939, 943, 3, 196, 98, 0, 940, 943, 3, 198, 99, 0, 941, 943, 3, 200, 100, 0, 942, 936, 1, 0, 0, 0, 942, 937, 1, 0, 0, 0, 942, 938, 1, 0, 0, 0, 942, 939, 1, 0, 0, 0, 942, 940, 1, 0, 0, 0, 942, 941, 1, 0, 0, 0, 943, 189, 1, 0, 0, 0, 944, 945, 5, 81, 0, 0, 945, 946, 3, 94, 47, 0, 946, 947, 3, 208, 104, 0, 947, 191, 1, 0, 0, 0, 948, 949, 7, 17, 0, 0, 949, 193, 1, 0, 0, 0, 950, 952, 7, 0, 0, 0, 951, 950, 1, 0, 0, 0, 951, 952, 1, 0, 0, 0, 952, 953, 1, 0, 0, 0, 953, 954, 5, 330, 0, 0, 954, 195, 1, 0, 0, 0, 955, 957, 7, 0, 0, 0, 956, 955, 1, 0, 0, 0, 956, 957, 1, 0, 0, 0, 957, 958, 1, 0, 0, 0, 958, 959, 5, 331, 0, 0, 959, 197, 1, 0, 0, 0, 960, 961, 7, 18, 0, 0, 961, 199, 1, 0, 0, 0, 962, 966, 3, 202, 101, 0, 963, 966, 3, 204, 102, 0, 964, 966, 3, 206, 103, 0, 965, 962, 1, 0, 0, 0, 965, 963, 1, 0, 0, 0, 965, 964, 1, 0, 0, 0, 966, 201, 1, 0, 0, 0, 967, 968, 5, 212, 0, 0, 968, 969, 3, 192, 96, 0, 969, 203, 1, 0, 0, 0, 970, 971, 5, 241, 0, 0, 971, 972, 3, 192, 96, 0, 972, 205, 1, 0, 0, 0, 973, 974, 5, 243, 0, 0, 974, 975, 3, 192, 96, 0, 975, 207, 1, 0, 0, 0, 976, 977, 7, 19, 0, 0, 977, 209, 1, 0, 0, 0, 978, 979, 7, 20, 0, 0, 979, 211, 1, 0, 0, 0, 980, 981, 5, 125, 0, 0, 981, 986, 3, 188, 94, 0, 982, 983, 5, 110, 0, 0, 983, 985, 3, 188, 94, 0, 984, 982, 1, 0, 0, 0, 985, 988, 1, 0, 0, 0, 986, 984, 1, 0, 0, 0, 986, 987, 1, 0, 0, 0, 987, 989, 1, 0, 0, 0, 988, 986, 1, 0, 0, 0, 989, 990, 5, 126, 0, 0, 990, 213, 1, 0, 0, 0, 991, 996, 3, 220, 110, 0, 992, 993, 5, 111, 0, 0, 993, 995, 3, 220, 110, 0, 994, 992, 1, 0, 0, 0, 995, 998, 1, 0, 0, 0, 996, 994, 1, 0, 0, 0, 996, 997, 1, 0, 0, 0, 997, 215, 1, 0, 0, 0, 998, 996, 1, 0, 0, 0, 999, 1004, 3, 222, 111, 0, 1000, 1001, 5, 111, 0, 0, 1001, 1003, 3, 220, 110, 0, 1002, 1000, 1, 0, 0, 0, 1003, 1006, 1, 0, 0, 0, 1004, 1002, 1, 0, 0, 0, 1004, 1005, 1, 0, 0, 0, 1005, 217, 1, 0, 0, 0, 1006, 1004, 1, 0, 0, 0, 1007, 1012, 3, 224, 112, 0, 1008, 1009, 5, 111, 0, 0, 1009, 1011, 3, 224, 112, 0, 1010, 1008, 1, 0, 0, 0, 1011, 1014, 1, 0, 0, 0, 1012, 1010, 1, 0, 0, 0, 1012, 1013, 1, 0, 0, 0, 1013, 219, 1, 0, 0, 0, 1014, 1012, 1, 0, 0, 0, 1015, 1017, 5, 111, 0, 0, 1016, 1015, 1, 0, 0, 0, 1016, 1017, 1, 0, 0, 0, 1017, 1018, 1, 0, 0, 0, 1018, 1026, 5, 328, 0, 0, 1019, 1020, 5, 131, 0, 0, 1020, 1021, 3, 220, 110, 0, 1021, 1022, 5, 131, 0, 0, 1022, 1026, 1, 0, 0, 0, 1023, 1026, 5, 335, 0, 0, 1024, 1026, 3, 226, 113, 0, 1025, 1016, 1, 0, 0, 0, 1025, 1019, 1, 0, 0, 0, 1025, 1023, 1, 0, 0, 0, 1025, 1024, 1, 0, 0, 0, 1026, 221, 1, 0, 0, 0, 1027, 1029, 5, 329, 0, 0, 1028, 1027, 1, 0, 0, 0, 1028, 1029, 1, 0, 0, 0, 1029, 1030, 1, 0, 0, 0, 1030, 1031, 3, 220, 110, 0, 1031, 223, 1, 0, 0, 0, 1032, 1037, 3, 220, 110, 0, 1033, 1034, 5, 122, 0, 0, 1034, 1036, 3, 220, 110, 0, 1035, 1033, 1, 0, 0, 0, 1036, 1039, 1, 0, 0, 0, 1037, 1035, 1, 0, 0, 0, 1037, 1038, 1, 0, 0, 0, 1038, 1041, 1, 0, 0, 0, 1039, 1037, 1, 0, 0, 0, 1040, 1042, 5, 122, 0, 0, 1041, 1040, 1, 0, 0, 0, 1041, 1042, 1, 0, 0, 0, 1042, 1056, 1, 0, 0, 0, 1043, 1044, 5, 129, 0, 0, 1044, 1045, 3, 224, 112, 0, 1045, 1046, 5, 129, 0, 0, 1046, 1056, 1, 0, 0, 0, 1047, 1048, 5, 130, 0, 0, 1048, 1049, 3, 224, 112, 0, 1049, 1050, 5, 130, 0, 0, 1050, 1056, 1, 0, 0, 0, 1051, 1052, 5, 131, 0, 0, 1052, 1053, 3, 224, 112, 0, 1053, 1054, 5, 131, 0, 0, 1054, 1056, 1, 0, 0, 0, 1055, 1032, 1, 0, 0, 0, 1055, 1043, 1, 0, 0, 0, 1055, 1047, 1, 0, 0, 0, 1055, 1051, 1, 0, 0, 0, 1056, 225, 1, 0, 0, 0, 1057, 1158, 5, 31, 0, 0, 1058, 1158, 3, 210, 105, 0, 1059, 1158, 5, 320, 0, 0, 1060, 1158, 3, 132, 66, 0, 1061, 1158, 3, 140, 70, 0, 1062, 1158, 3, 208, 104, 0, 1063, 1158, 3, 156, 78, 0, 1064, 1158, 3, 178, 89, 0, 1065, 1158, 3, 152, 76, 0, 1066, 1158, 3, 180, 90, 0, 1067, 1158, 5, 2, 0, 0, 1068, 1158, 5, 3, 0, 0, 1069, 1158, 5, 4, 0, 0, 1070, 1158, 5, 5, 0, 0, 1071, 1158, 5, 6, 0, 0, 1072, 1158, 5, 7, 0, 0, 1073, 1158, 5, 8, 0, 0, 1074, 1158, 5, 9, 0, 0, 1075, 1158, 5, 10, 0, 0, 1076, 1158, 5, 11, 0, 0, 1077, 1158, 5, 12, 0, 0, 1078, 1158, 5, 13, 0, 0, 1079, 1158, 5, 14, 0, 0, 1080, 1158, 5, 15, 0, 0, 1081, 1158, 5, 16, 0, 0, 1082, 1158, 5, 17, 0, 0, 1083, 1158, 5, 18, 0, 0, 1084, 1158, 5, 19, 0, 0, 1085, 1158, 5, 20, 0, 0, 1086, 1158, 5, 21, 0, 0, 1087, 1158, 5, 22, 0, 0, 1088, 1158, 5, 23, 0, 0, 1089, 1158, 5, 24, 0, 0, 1090, 1158, 5, 25, 0, 0, 1091, 1158, 5, 26, 0, 0, 1092, 1158, 5, 29, 0, 0, 1093, 1158, 5, 30, 0, 0, 1094, 1158, 5, 32, 0, 0, 1095, 1158, 5, 33, 0, 0, 1096, 1158, 5, 34, 0, 0, 1097, 1158, 5, 36, 0, 0, 1098, 1158, 5, 37, 0, 0, 1099, 1158, 5, 38, 0, 0, 1100, 1158, 5, 39, 0, 0, 1101, 1158, 5, 40, 0, 0, 1102, 1158, 5, 41, 0, 0, 1103, 1158, 5, 42, 0, 0, 1104, 1158, 5, 43, 0, 0, 1105, 1158, 5, 44, 0, 0, 1106, 1158, 5, 45, 0, 0, 1107, 1158, 5, 46, 0, 0, 1108, 1158, 5, 47, 0, 0, 1109, 1158, 5, 48, 0, 0, 1110, 1158, 5, 49, 0, 0, 1111, 1158, 5, 50, 0, 0, 1112, 1158, 5, 51, 0, 0, 1113, 1158, 5, 52, 0, 0, 1114, 1158, 5, 53, 0, 0, 1115, 1158, 5, 54, 0, 0, 1116, 1158, 5, 55, 0, 0, 1117, 1158, 5, 56, 0, 0, 1118, 1158, 5, 57, 0, 0, 1119, 1158, 5, 58, 0, 0, 1120, 1158, 5, 135, 0, 0, 1121, 1158, 5, 136, 0, 0, 1122, 1158, 5, 137, 0, 0, 1123, 1158, 5, 138, 0, 0, 1124, 1158, 5, 139, 0, 0, 1125, 1158, 5, 140, 0, 0, 1126, 1158, 5, 141, 0, 0, 1127, 1158, 5, 142, 0, 0, 1128, 1158, 5, 143, 0, 0, 1129, 1158, 5, 144, 0, 0, 1130, 1158, 5, 145, 0, 0, 1131, 1158, 5, 146, 0, 0, 1132, 1158, 5, 147, 0, 0, 1133, 1158, 5, 148, 0, 0, 1134, 1158, 5, 149, 0, 0, 1135, 1158, 5, 150, 0, 0, 1136, 1158, 5, 151, 0, 0, 1137, 1158, 5, 152, 0, 0, 1138, 1158, 5, 153, 0, 0, 1139, 1158, 5, 154, 0, 0, 1140, 1158, 5, 155, 0, 0, 1141, 1158, 5, 156, 0, 0, 1142, 1158, 5, 157, 0, 0, 1143, 1158, 5, 158, 0, 0, 1144, 1158, 5, 159, 0, 0, 1145, 1158, 5, 160, 0, 0, 1146, 1158, 5, 161, 0, 0, 1147, 1158, 5, 162, 0, 0, 1148, 1158, 5, 163, 0, 0, 1149, 1158, 5, 164, 0, 0, 1150, 1158, 5, 165, 0, 0, 1151, 1158, 5, 166, 0, 0, 1152, 1158, 5, 167, 0, 0, 1153, 1158, 5, 168, 0, 0, 1154, 1158, 5, 169, 0, 0, 1155, 1158, 5, 170, 0, 0, 1156, 1158, 5, 171, 0, 0, 1157, 1057, 1, 0, 0, 0, 1157, 1058, 1, 0, 0, 0, 1157, 1059, 1, 0, 0, 0, 1157, 1060, 1, 0, 0, 0, 1157, 1061, 1, 0, 0, 0, 1157, 1062, 1, 0, 0, 0, 1157, 1063, 1, 0, 0, 0, 1157, 1064, 1, 0, 0, 0, 1157, 1065, 1, 0, 0, 0, 1157, 1066, 1, 0, 0, 0, 1157, 1067, 1, 0, 0, 0, 1157, 1068, 1, 0, 0, 0, 1157, 1069, 1, 0, 0, 0, 1157, 1070, 1, 0, 0, 0, 1157, 1071, 1, 0, 0, 0, 1157, 1072, 1, 0, 0, 0, 1157, 1073, 1, 0, 0, 0, 1157, 1074, 1, 0, 0, 0, 1157, 1075, 1, 0, 0, 0, 1157, 1076, 1, 0, 0, 0, 1157, 1077, 1, 0, 0, 0, 1157, 1078, 1, 0, 0, 0, 1157, 1079, 1, 0, 0, 0, 1157, 1080, 1, 0, 0, 0, 1157, 1081, 1, 0, 0, 0, 1157, 1082, 1, 0, 0, 0, 1157, 1083, 1, 0, 0, 0, 1157, 1084, 1, 0, 0, 0, 1157, 1085, 1, 0, 0, 0, 1157, 1086, 1, 0, 0, 0, 1157, 1087, 1, 0, 0, 0, 1157, 1088, 1, 0, 0, 0, 1157, 1089, 1, 0, 0, 0, 1157, 1090, 1, 0, 0, 0, 1157, 1091, 1, 0, 0, 0, 1157, 1092, 1, 0, 0, 0, 1157, 1093, 1, 0, 0, 0, 1157, 1094, 1, 0, 0, 0, 1157, 1095, 1, 0, 0, 0, 1157, 1096, 1, 0, 0, 0, 1157, 1097, 1, 0, 0, 0, 1157, 1098, 1, 0, 0, 0, 1157, 1099, 1, 0, 0, 0, 1157, 1100, 1, 0, 0, 0, 1157, 1101, 1, 0, 0, 0, 1157, 1102, 1, 0, 0, 0, 1157, 1103, 1, 0, 0, 0, 1157, 1104, 1, 0, 0, 0, 1157, 1105, 1, 0, 0, 0, 1157, 1106, 1, 0, 0, 0, 1157, 1107, 1, 0, 0, 0, 1157, 1108, 1, 0, 0, 0, 1157, 1109, 1, 0, 0, 0, 1157, 1110, 1, 0, 0, 0, 1157, 1111, 1, 0, 0, 0, 1157, 1112, 1, 0, 0, 0, 1157, 1113, 1, 0, 0, 0, 1157, 1114, 1, 0, 0, 0, 1157, 1115, 1, 0, 0, 0, 1157, 1116, 1, 0, 0, 0, 1157, 1117, 1, 0, 0, 0, 1157, 1118, 1, 0, 0, 0, 1157, 1119, 1, 0, 0, 0, 1157, 1120, 1, 0, 0, 0, 1157, 1121, 1, 0, 0, 0, 1157, 1122, 1, 0, 0, 0, 1157, 1123, 1, 0, 0, 0, 1157, 1124, 1, 0, 0, 0, 1157, 1125, 1, 0, 0, 0, 1157, 1126, 1, 0, 0, 0, 1157, 1127, 1, 0, 0, 0, 1157, 1128, 1, 0, 0, 0, 1157, 1129, 1, 0, 0, 0, 1157, 1130, 1, 0, 0, 0, 1157, 1131, 1, 0, 0, 0, 1157, 1132, 1, 0, 0, 0, 1157, 1133, 1, 0, 0, 0, 1157, 1134, 1, 0, 0, 0, 1157, 1135, 1, 0, 0, 0, 1157, 1136, 1, 0, 0, 0, 1157, 1137, 1, 0, 0, 0, 1157, 1138, 1, 0, 0, 0, 1157, 1139, 1, 0, 0, 0, 1157, 1140, 1, 0, 0, 0, 1157, 1141, 1, 0, 0, 0, 1157, 1142, 1, 0, 0, 0, 1157, 1143, 1, 0, 0, 0, 1157, 1144, 1, 0, 0, 0, 1157, 1145, 1, 0, 0, 0, 1157, 1146, 1, 0, 0, 0, 1157, 1147, 1, 0, 0, 0, 1157, 1148, 1, 0, 0, 0, 1157, 1149, 1, 0, 0, 0, 1157, 1150, 1, 0, 0, 0, 1157, 1151, 1, 0, 0, 0, 1157, 1152, 1, 0, 0, 0, 1157, 1153, 1, 0, 0, 0, 1157, 1154, 1, 0, 0, 0, 1157, 1155, 1, 0, 0, 0, 1157, 1156, 1, 0, 0, 0, 1158, 227, 1, 0, 0, 0, 86, 229, 242, 248, 266, 269, 273, 279, 284, 297, 307, 314, 319, 324, 331, 335, 340, 344, 350, 355, 366, 371, 375, 379, 383, 388, 402, 413, 421, 433, 439, 478, 484, 503, 510, 529, 534, 542, 551, 561, 578, 587, 602, 610, 617, 623, 625, 636, 648, 656, 658, 665, 678, 689, 702, 712, 719, 731, 739, 743, 768, 801, 809, 816, 819, 824, 842, 846, 850, 856, 881, 909, 942, 951, 956, 965, 986, 996, 1004, 1012, 1016, 1025, 1028, 1037, 1041, 1055, 1157] \ No newline at end of file diff --git a/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.tokens b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.tokens new file mode 100644 index 000000000000..4779948fd379 --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.tokens @@ -0,0 +1,659 @@ +SPACE=1 +SEARCH=2 +DESCRIBE=3 +SHOW=4 +FROM=5 +WHERE=6 +FIELDS=7 +RENAME=8 +STATS=9 +DEDUP=10 +SORT=11 +EVAL=12 +HEAD=13 +TOP=14 +RARE=15 +PARSE=16 +METHOD=17 +REGEX=18 +PUNCT=19 +GROK=20 +PATTERN=21 +PATTERNS=22 +NEW_FIELD=23 +KMEANS=24 +AD=25 +ML=26 +AS=27 +BY=28 +SOURCE=29 +INDEX=30 +D=31 +DESC=32 +DATASOURCES=33 +SORTBY=34 +AUTO=35 +STR=36 +IP=37 +NUM=38 +KEEPEMPTY=39 +CONSECUTIVE=40 +DEDUP_SPLITVALUES=41 +PARTITIONS=42 +ALLNUM=43 +DELIM=44 +CENTROIDS=45 +ITERATIONS=46 +DISTANCE_TYPE=47 +NUMBER_OF_TREES=48 +SHINGLE_SIZE=49 +SAMPLE_SIZE=50 +OUTPUT_AFTER=51 +TIME_DECAY=52 +ANOMALY_RATE=53 +CATEGORY_FIELD=54 +TIME_FIELD=55 +TIME_ZONE=56 +TRAINING_DATA_SIZE=57 +ANOMALY_SCORE_THRESHOLD=58 +CASE=59 +IN=60 +NOT=61 +OR=62 +AND=63 +XOR=64 +TRUE=65 +FALSE=66 +REGEXP=67 +CONVERT_TZ=68 +DATETIME=69 +DAY=70 +DAY_HOUR=71 +DAY_MICROSECOND=72 +DAY_MINUTE=73 +DAY_OF_YEAR=74 +DAY_SECOND=75 +HOUR=76 +HOUR_MICROSECOND=77 +HOUR_MINUTE=78 +HOUR_OF_DAY=79 +HOUR_SECOND=80 +INTERVAL=81 +MICROSECOND=82 +MILLISECOND=83 +MINUTE=84 +MINUTE_MICROSECOND=85 +MINUTE_OF_DAY=86 +MINUTE_OF_HOUR=87 +MINUTE_SECOND=88 +MONTH=89 +MONTH_OF_YEAR=90 +QUARTER=91 +SECOND=92 +SECOND_MICROSECOND=93 +SECOND_OF_MINUTE=94 +WEEK=95 +WEEK_OF_YEAR=96 +YEAR=97 +YEAR_MONTH=98 +DATAMODEL=99 +LOOKUP=100 +SAVEDSEARCH=101 +INT=102 +INTEGER=103 +DOUBLE=104 +LONG=105 +FLOAT=106 +STRING=107 +BOOLEAN=108 +PIPE=109 +COMMA=110 +DOT=111 +EQUAL=112 +GREATER=113 +LESS=114 +NOT_GREATER=115 +NOT_LESS=116 +NOT_EQUAL=117 +PLUS=118 +MINUS=119 +STAR=120 +DIVIDE=121 +MODULE=122 +EXCLAMATION_SYMBOL=123 +COLON=124 +LT_PRTHS=125 +RT_PRTHS=126 +LT_SQR_PRTHS=127 +RT_SQR_PRTHS=128 +SINGLE_QUOTE=129 +DOUBLE_QUOTE=130 +BACKTICK=131 +BIT_NOT_OP=132 +BIT_AND_OP=133 +BIT_XOR_OP=134 +AVG=135 +COUNT=136 +DISTINCT_COUNT=137 +ESTDC=138 +ESTDC_ERROR=139 +MAX=140 +MEAN=141 +MEDIAN=142 +MIN=143 +MODE=144 +RANGE=145 +STDEV=146 +STDEVP=147 +SUM=148 +SUMSQ=149 +VAR_SAMP=150 +VAR_POP=151 +STDDEV_SAMP=152 +STDDEV_POP=153 +PERCENTILE=154 +TAKE=155 +FIRST=156 +LAST=157 +LIST=158 +VALUES=159 +EARLIEST=160 +EARLIEST_TIME=161 +LATEST=162 +LATEST_TIME=163 +PER_DAY=164 +PER_HOUR=165 +PER_MINUTE=166 +PER_SECOND=167 +RATE=168 +SPARKLINE=169 +C=170 +DC=171 +ABS=172 +CBRT=173 +CEIL=174 +CEILING=175 +CONV=176 +CRC32=177 +E=178 +EXP=179 +FLOOR=180 +LN=181 +LOG=182 +LOG10=183 +LOG2=184 +MOD=185 +PI=186 +POSITION=187 +POW=188 +POWER=189 +RAND=190 +ROUND=191 +SIGN=192 +SQRT=193 +TRUNCATE=194 +ACOS=195 +ASIN=196 +ATAN=197 +ATAN2=198 +COS=199 +COT=200 +DEGREES=201 +RADIANS=202 +SIN=203 +TAN=204 +ADDDATE=205 +ADDTIME=206 +CURDATE=207 +CURRENT_DATE=208 +CURRENT_TIME=209 +CURRENT_TIMESTAMP=210 +CURTIME=211 +DATE=212 +DATEDIFF=213 +DATE_ADD=214 +DATE_FORMAT=215 +DATE_SUB=216 +DAYNAME=217 +DAYOFMONTH=218 +DAYOFWEEK=219 +DAYOFYEAR=220 +DAY_OF_MONTH=221 +DAY_OF_WEEK=222 +EXTRACT=223 +FROM_DAYS=224 +FROM_UNIXTIME=225 +GET_FORMAT=226 +LAST_DAY=227 +LOCALTIME=228 +LOCALTIMESTAMP=229 +MAKEDATE=230 +MAKETIME=231 +MONTHNAME=232 +NOW=233 +PERIOD_ADD=234 +PERIOD_DIFF=235 +SEC_TO_TIME=236 +STR_TO_DATE=237 +SUBDATE=238 +SUBTIME=239 +SYSDATE=240 +TIME=241 +TIMEDIFF=242 +TIMESTAMP=243 +TIMESTAMPADD=244 +TIMESTAMPDIFF=245 +TIME_FORMAT=246 +TIME_TO_SEC=247 +TO_DAYS=248 +TO_SECONDS=249 +UNIX_TIMESTAMP=250 +UTC_DATE=251 +UTC_TIME=252 +UTC_TIMESTAMP=253 +WEEKDAY=254 +YEARWEEK=255 +SUBSTR=256 +SUBSTRING=257 +LTRIM=258 +RTRIM=259 +TRIM=260 +TO=261 +LOWER=262 +UPPER=263 +CONCAT=264 +CONCAT_WS=265 +LENGTH=266 +STRCMP=267 +RIGHT=268 +LEFT=269 +ASCII=270 +LOCATE=271 +REPLACE=272 +REVERSE=273 +CAST=274 +LIKE=275 +ISNULL=276 +ISNOTNULL=277 +IFNULL=278 +NULLIF=279 +IF=280 +TYPEOF=281 +MATCH=282 +MATCH_PHRASE=283 +MATCH_PHRASE_PREFIX=284 +MATCH_BOOL_PREFIX=285 +SIMPLE_QUERY_STRING=286 +MULTI_MATCH=287 +QUERY_STRING=288 +ALLOW_LEADING_WILDCARD=289 +ANALYZE_WILDCARD=290 +ANALYZER=291 +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY=292 +BOOST=293 +CUTOFF_FREQUENCY=294 +DEFAULT_FIELD=295 +DEFAULT_OPERATOR=296 +ENABLE_POSITION_INCREMENTS=297 +ESCAPE=298 +FLAGS=299 +FUZZY_MAX_EXPANSIONS=300 +FUZZY_PREFIX_LENGTH=301 +FUZZY_TRANSPOSITIONS=302 +FUZZY_REWRITE=303 +FUZZINESS=304 +LENIENT=305 +LOW_FREQ_OPERATOR=306 +MAX_DETERMINIZED_STATES=307 +MAX_EXPANSIONS=308 +MINIMUM_SHOULD_MATCH=309 +OPERATOR=310 +PHRASE_SLOP=311 +PREFIX_LENGTH=312 +QUOTE_ANALYZER=313 +QUOTE_FIELD_SUFFIX=314 +REWRITE=315 +SLOP=316 +TIE_BREAKER=317 +TYPE=318 +ZERO_TERMS_QUERY=319 +SPAN=320 +MS=321 +S=322 +M=323 +H=324 +W=325 +Q=326 +Y=327 +ID=328 +CLUSTER=329 +INTEGER_LITERAL=330 +DECIMAL_LITERAL=331 +ID_DATE_SUFFIX=332 +DQUOTA_STRING=333 +SQUOTA_STRING=334 +BQUOTA_STRING=335 +ERROR_RECOGNITION=336 +'SEARCH'=2 +'DESCRIBE'=3 +'SHOW'=4 +'FROM'=5 +'WHERE'=6 +'FIELDS'=7 +'RENAME'=8 +'STATS'=9 +'DEDUP'=10 +'SORT'=11 +'EVAL'=12 +'HEAD'=13 +'TOP'=14 +'RARE'=15 +'PARSE'=16 +'METHOD'=17 +'REGEX'=18 +'PUNCT'=19 +'GROK'=20 +'PATTERN'=21 +'PATTERNS'=22 +'NEW_FIELD'=23 +'KMEANS'=24 +'AD'=25 +'ML'=26 +'AS'=27 +'BY'=28 +'SOURCE'=29 +'INDEX'=30 +'D'=31 +'DESC'=32 +'DATASOURCES'=33 +'SORTBY'=34 +'AUTO'=35 +'STR'=36 +'IP'=37 +'NUM'=38 +'KEEPEMPTY'=39 +'CONSECUTIVE'=40 +'DEDUP_SPLITVALUES'=41 +'PARTITIONS'=42 +'ALLNUM'=43 +'DELIM'=44 +'CENTROIDS'=45 +'ITERATIONS'=46 +'DISTANCE_TYPE'=47 +'NUMBER_OF_TREES'=48 +'SHINGLE_SIZE'=49 +'SAMPLE_SIZE'=50 +'OUTPUT_AFTER'=51 +'TIME_DECAY'=52 +'ANOMALY_RATE'=53 +'CATEGORY_FIELD'=54 +'TIME_FIELD'=55 +'TIME_ZONE'=56 +'TRAINING_DATA_SIZE'=57 +'ANOMALY_SCORE_THRESHOLD'=58 +'CASE'=59 +'IN'=60 +'NOT'=61 +'OR'=62 +'AND'=63 +'XOR'=64 +'TRUE'=65 +'FALSE'=66 +'REGEXP'=67 +'CONVERT_TZ'=68 +'DATETIME'=69 +'DAY'=70 +'DAY_HOUR'=71 +'DAY_MICROSECOND'=72 +'DAY_MINUTE'=73 +'DAY_OF_YEAR'=74 +'DAY_SECOND'=75 +'HOUR'=76 +'HOUR_MICROSECOND'=77 +'HOUR_MINUTE'=78 +'HOUR_OF_DAY'=79 +'HOUR_SECOND'=80 +'INTERVAL'=81 +'MICROSECOND'=82 +'MILLISECOND'=83 +'MINUTE'=84 +'MINUTE_MICROSECOND'=85 +'MINUTE_OF_DAY'=86 +'MINUTE_OF_HOUR'=87 +'MINUTE_SECOND'=88 +'MONTH'=89 +'MONTH_OF_YEAR'=90 +'QUARTER'=91 +'SECOND'=92 +'SECOND_MICROSECOND'=93 +'SECOND_OF_MINUTE'=94 +'WEEK'=95 +'WEEK_OF_YEAR'=96 +'YEAR'=97 +'YEAR_MONTH'=98 +'DATAMODEL'=99 +'LOOKUP'=100 +'SAVEDSEARCH'=101 +'INT'=102 +'INTEGER'=103 +'DOUBLE'=104 +'LONG'=105 +'FLOAT'=106 +'STRING'=107 +'BOOLEAN'=108 +'|'=109 +','=110 +'.'=111 +'='=112 +'>'=113 +'<'=114 +'+'=118 +'-'=119 +'*'=120 +'/'=121 +'%'=122 +'!'=123 +':'=124 +'('=125 +')'=126 +'['=127 +']'=128 +'\''=129 +'"'=130 +'`'=131 +'~'=132 +'&'=133 +'^'=134 +'AVG'=135 +'COUNT'=136 +'DISTINCT_COUNT'=137 +'ESTDC'=138 +'ESTDC_ERROR'=139 +'MAX'=140 +'MEAN'=141 +'MEDIAN'=142 +'MIN'=143 +'MODE'=144 +'RANGE'=145 +'STDEV'=146 +'STDEVP'=147 +'SUM'=148 +'SUMSQ'=149 +'VAR_SAMP'=150 +'VAR_POP'=151 +'STDDEV_SAMP'=152 +'STDDEV_POP'=153 +'PERCENTILE'=154 +'TAKE'=155 +'FIRST'=156 +'LAST'=157 +'LIST'=158 +'VALUES'=159 +'EARLIEST'=160 +'EARLIEST_TIME'=161 +'LATEST'=162 +'LATEST_TIME'=163 +'PER_DAY'=164 +'PER_HOUR'=165 +'PER_MINUTE'=166 +'PER_SECOND'=167 +'RATE'=168 +'SPARKLINE'=169 +'C'=170 +'DC'=171 +'ABS'=172 +'CBRT'=173 +'CEIL'=174 +'CEILING'=175 +'CONV'=176 +'CRC32'=177 +'E'=178 +'EXP'=179 +'FLOOR'=180 +'LN'=181 +'LOG'=182 +'LOG10'=183 +'LOG2'=184 +'MOD'=185 +'PI'=186 +'POSITION'=187 +'POW'=188 +'POWER'=189 +'RAND'=190 +'ROUND'=191 +'SIGN'=192 +'SQRT'=193 +'TRUNCATE'=194 +'ACOS'=195 +'ASIN'=196 +'ATAN'=197 +'ATAN2'=198 +'COS'=199 +'COT'=200 +'DEGREES'=201 +'RADIANS'=202 +'SIN'=203 +'TAN'=204 +'ADDDATE'=205 +'ADDTIME'=206 +'CURDATE'=207 +'CURRENT_DATE'=208 +'CURRENT_TIME'=209 +'CURRENT_TIMESTAMP'=210 +'CURTIME'=211 +'DATE'=212 +'DATEDIFF'=213 +'DATE_ADD'=214 +'DATE_FORMAT'=215 +'DATE_SUB'=216 +'DAYNAME'=217 +'DAYOFMONTH'=218 +'DAYOFWEEK'=219 +'DAYOFYEAR'=220 +'DAY_OF_MONTH'=221 +'DAY_OF_WEEK'=222 +'EXTRACT'=223 +'FROM_DAYS'=224 +'FROM_UNIXTIME'=225 +'GET_FORMAT'=226 +'LAST_DAY'=227 +'LOCALTIME'=228 +'LOCALTIMESTAMP'=229 +'MAKEDATE'=230 +'MAKETIME'=231 +'MONTHNAME'=232 +'NOW'=233 +'PERIOD_ADD'=234 +'PERIOD_DIFF'=235 +'SEC_TO_TIME'=236 +'STR_TO_DATE'=237 +'SUBDATE'=238 +'SUBTIME'=239 +'SYSDATE'=240 +'TIME'=241 +'TIMEDIFF'=242 +'TIMESTAMP'=243 +'TIMESTAMPADD'=244 +'TIMESTAMPDIFF'=245 +'TIME_FORMAT'=246 +'TIME_TO_SEC'=247 +'TO_DAYS'=248 +'TO_SECONDS'=249 +'UNIX_TIMESTAMP'=250 +'UTC_DATE'=251 +'UTC_TIME'=252 +'UTC_TIMESTAMP'=253 +'WEEKDAY'=254 +'YEARWEEK'=255 +'SUBSTR'=256 +'SUBSTRING'=257 +'LTRIM'=258 +'RTRIM'=259 +'TRIM'=260 +'TO'=261 +'LOWER'=262 +'UPPER'=263 +'CONCAT'=264 +'CONCAT_WS'=265 +'LENGTH'=266 +'STRCMP'=267 +'RIGHT'=268 +'LEFT'=269 +'ASCII'=270 +'LOCATE'=271 +'REPLACE'=272 +'REVERSE'=273 +'CAST'=274 +'LIKE'=275 +'ISNULL'=276 +'ISNOTNULL'=277 +'IFNULL'=278 +'NULLIF'=279 +'IF'=280 +'TYPEOF'=281 +'MATCH'=282 +'MATCH_PHRASE'=283 +'MATCH_PHRASE_PREFIX'=284 +'MATCH_BOOL_PREFIX'=285 +'SIMPLE_QUERY_STRING'=286 +'MULTI_MATCH'=287 +'QUERY_STRING'=288 +'ALLOW_LEADING_WILDCARD'=289 +'ANALYZE_WILDCARD'=290 +'ANALYZER'=291 +'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY'=292 +'BOOST'=293 +'CUTOFF_FREQUENCY'=294 +'DEFAULT_FIELD'=295 +'DEFAULT_OPERATOR'=296 +'ENABLE_POSITION_INCREMENTS'=297 +'ESCAPE'=298 +'FLAGS'=299 +'FUZZY_MAX_EXPANSIONS'=300 +'FUZZY_PREFIX_LENGTH'=301 +'FUZZY_TRANSPOSITIONS'=302 +'FUZZY_REWRITE'=303 +'FUZZINESS'=304 +'LENIENT'=305 +'LOW_FREQ_OPERATOR'=306 +'MAX_DETERMINIZED_STATES'=307 +'MAX_EXPANSIONS'=308 +'MINIMUM_SHOULD_MATCH'=309 +'OPERATOR'=310 +'PHRASE_SLOP'=311 +'PREFIX_LENGTH'=312 +'QUOTE_ANALYZER'=313 +'QUOTE_FIELD_SUFFIX'=314 +'REWRITE'=315 +'SLOP'=316 +'TIE_BREAKER'=317 +'TYPE'=318 +'ZERO_TERMS_QUERY'=319 +'SPAN'=320 +'MS'=321 +'S'=322 +'M'=323 +'H'=324 +'W'=325 +'Q'=326 +'Y'=327 diff --git a/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.ts b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.ts new file mode 100644 index 000000000000..a3fa6b2219d1 --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParser.ts @@ -0,0 +1,12797 @@ +// Generated from ./src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLParser.g4 by ANTLR 4.13.1 + +import * as antlr from "antlr4ng"; +import { Token } from "antlr4ng"; + +import { OpenSearchPPLParserVisitor } from "./OpenSearchPPLParserVisitor.js"; + +// for running tests with parameters, TODO: discuss strategy for typed parameters in CI +// eslint-disable-next-line no-unused-vars +type int = number; + + +export class OpenSearchPPLParser extends antlr.Parser { + public static readonly SPACE = 1; + public static readonly SEARCH = 2; + public static readonly DESCRIBE = 3; + public static readonly SHOW = 4; + public static readonly FROM = 5; + public static readonly WHERE = 6; + public static readonly FIELDS = 7; + public static readonly RENAME = 8; + public static readonly STATS = 9; + public static readonly DEDUP = 10; + public static readonly SORT = 11; + public static readonly EVAL = 12; + public static readonly HEAD = 13; + public static readonly TOP = 14; + public static readonly RARE = 15; + public static readonly PARSE = 16; + public static readonly METHOD = 17; + public static readonly REGEX = 18; + public static readonly PUNCT = 19; + public static readonly GROK = 20; + public static readonly PATTERN = 21; + public static readonly PATTERNS = 22; + public static readonly NEW_FIELD = 23; + public static readonly KMEANS = 24; + public static readonly AD = 25; + public static readonly ML = 26; + public static readonly AS = 27; + public static readonly BY = 28; + public static readonly SOURCE = 29; + public static readonly INDEX = 30; + public static readonly D = 31; + public static readonly DESC = 32; + public static readonly DATASOURCES = 33; + public static readonly SORTBY = 34; + public static readonly AUTO = 35; + public static readonly STR = 36; + public static readonly IP = 37; + public static readonly NUM = 38; + public static readonly KEEPEMPTY = 39; + public static readonly CONSECUTIVE = 40; + public static readonly DEDUP_SPLITVALUES = 41; + public static readonly PARTITIONS = 42; + public static readonly ALLNUM = 43; + public static readonly DELIM = 44; + public static readonly CENTROIDS = 45; + public static readonly ITERATIONS = 46; + public static readonly DISTANCE_TYPE = 47; + public static readonly NUMBER_OF_TREES = 48; + public static readonly SHINGLE_SIZE = 49; + public static readonly SAMPLE_SIZE = 50; + public static readonly OUTPUT_AFTER = 51; + public static readonly TIME_DECAY = 52; + public static readonly ANOMALY_RATE = 53; + public static readonly CATEGORY_FIELD = 54; + public static readonly TIME_FIELD = 55; + public static readonly TIME_ZONE = 56; + public static readonly TRAINING_DATA_SIZE = 57; + public static readonly ANOMALY_SCORE_THRESHOLD = 58; + public static readonly CASE = 59; + public static readonly IN = 60; + public static readonly NOT = 61; + public static readonly OR = 62; + public static readonly AND = 63; + public static readonly XOR = 64; + public static readonly TRUE = 65; + public static readonly FALSE = 66; + public static readonly REGEXP = 67; + public static readonly CONVERT_TZ = 68; + public static readonly DATETIME = 69; + public static readonly DAY = 70; + public static readonly DAY_HOUR = 71; + public static readonly DAY_MICROSECOND = 72; + public static readonly DAY_MINUTE = 73; + public static readonly DAY_OF_YEAR = 74; + public static readonly DAY_SECOND = 75; + public static readonly HOUR = 76; + public static readonly HOUR_MICROSECOND = 77; + public static readonly HOUR_MINUTE = 78; + public static readonly HOUR_OF_DAY = 79; + public static readonly HOUR_SECOND = 80; + public static readonly INTERVAL = 81; + public static readonly MICROSECOND = 82; + public static readonly MILLISECOND = 83; + public static readonly MINUTE = 84; + public static readonly MINUTE_MICROSECOND = 85; + public static readonly MINUTE_OF_DAY = 86; + public static readonly MINUTE_OF_HOUR = 87; + public static readonly MINUTE_SECOND = 88; + public static readonly MONTH = 89; + public static readonly MONTH_OF_YEAR = 90; + public static readonly QUARTER = 91; + public static readonly SECOND = 92; + public static readonly SECOND_MICROSECOND = 93; + public static readonly SECOND_OF_MINUTE = 94; + public static readonly WEEK = 95; + public static readonly WEEK_OF_YEAR = 96; + public static readonly YEAR = 97; + public static readonly YEAR_MONTH = 98; + public static readonly DATAMODEL = 99; + public static readonly LOOKUP = 100; + public static readonly SAVEDSEARCH = 101; + public static readonly INT = 102; + public static readonly INTEGER = 103; + public static readonly DOUBLE = 104; + public static readonly LONG = 105; + public static readonly FLOAT = 106; + public static readonly STRING = 107; + public static readonly BOOLEAN = 108; + public static readonly PIPE = 109; + public static readonly COMMA = 110; + public static readonly DOT = 111; + public static readonly EQUAL = 112; + public static readonly GREATER = 113; + public static readonly LESS = 114; + public static readonly NOT_GREATER = 115; + public static readonly NOT_LESS = 116; + public static readonly NOT_EQUAL = 117; + public static readonly PLUS = 118; + public static readonly MINUS = 119; + public static readonly STAR = 120; + public static readonly DIVIDE = 121; + public static readonly MODULE = 122; + public static readonly EXCLAMATION_SYMBOL = 123; + public static readonly COLON = 124; + public static readonly LT_PRTHS = 125; + public static readonly RT_PRTHS = 126; + public static readonly LT_SQR_PRTHS = 127; + public static readonly RT_SQR_PRTHS = 128; + public static readonly SINGLE_QUOTE = 129; + public static readonly DOUBLE_QUOTE = 130; + public static readonly BACKTICK = 131; + public static readonly BIT_NOT_OP = 132; + public static readonly BIT_AND_OP = 133; + public static readonly BIT_XOR_OP = 134; + public static readonly AVG = 135; + public static readonly COUNT = 136; + public static readonly DISTINCT_COUNT = 137; + public static readonly ESTDC = 138; + public static readonly ESTDC_ERROR = 139; + public static readonly MAX = 140; + public static readonly MEAN = 141; + public static readonly MEDIAN = 142; + public static readonly MIN = 143; + public static readonly MODE = 144; + public static readonly RANGE = 145; + public static readonly STDEV = 146; + public static readonly STDEVP = 147; + public static readonly SUM = 148; + public static readonly SUMSQ = 149; + public static readonly VAR_SAMP = 150; + public static readonly VAR_POP = 151; + public static readonly STDDEV_SAMP = 152; + public static readonly STDDEV_POP = 153; + public static readonly PERCENTILE = 154; + public static readonly TAKE = 155; + public static readonly FIRST = 156; + public static readonly LAST = 157; + public static readonly LIST = 158; + public static readonly VALUES = 159; + public static readonly EARLIEST = 160; + public static readonly EARLIEST_TIME = 161; + public static readonly LATEST = 162; + public static readonly LATEST_TIME = 163; + public static readonly PER_DAY = 164; + public static readonly PER_HOUR = 165; + public static readonly PER_MINUTE = 166; + public static readonly PER_SECOND = 167; + public static readonly RATE = 168; + public static readonly SPARKLINE = 169; + public static readonly C = 170; + public static readonly DC = 171; + public static readonly ABS = 172; + public static readonly CBRT = 173; + public static readonly CEIL = 174; + public static readonly CEILING = 175; + public static readonly CONV = 176; + public static readonly CRC32 = 177; + public static readonly E = 178; + public static readonly EXP = 179; + public static readonly FLOOR = 180; + public static readonly LN = 181; + public static readonly LOG = 182; + public static readonly LOG10 = 183; + public static readonly LOG2 = 184; + public static readonly MOD = 185; + public static readonly PI = 186; + public static readonly POSITION = 187; + public static readonly POW = 188; + public static readonly POWER = 189; + public static readonly RAND = 190; + public static readonly ROUND = 191; + public static readonly SIGN = 192; + public static readonly SQRT = 193; + public static readonly TRUNCATE = 194; + public static readonly ACOS = 195; + public static readonly ASIN = 196; + public static readonly ATAN = 197; + public static readonly ATAN2 = 198; + public static readonly COS = 199; + public static readonly COT = 200; + public static readonly DEGREES = 201; + public static readonly RADIANS = 202; + public static readonly SIN = 203; + public static readonly TAN = 204; + public static readonly ADDDATE = 205; + public static readonly ADDTIME = 206; + public static readonly CURDATE = 207; + public static readonly CURRENT_DATE = 208; + public static readonly CURRENT_TIME = 209; + public static readonly CURRENT_TIMESTAMP = 210; + public static readonly CURTIME = 211; + public static readonly DATE = 212; + public static readonly DATEDIFF = 213; + public static readonly DATE_ADD = 214; + public static readonly DATE_FORMAT = 215; + public static readonly DATE_SUB = 216; + public static readonly DAYNAME = 217; + public static readonly DAYOFMONTH = 218; + public static readonly DAYOFWEEK = 219; + public static readonly DAYOFYEAR = 220; + public static readonly DAY_OF_MONTH = 221; + public static readonly DAY_OF_WEEK = 222; + public static readonly EXTRACT = 223; + public static readonly FROM_DAYS = 224; + public static readonly FROM_UNIXTIME = 225; + public static readonly GET_FORMAT = 226; + public static readonly LAST_DAY = 227; + public static readonly LOCALTIME = 228; + public static readonly LOCALTIMESTAMP = 229; + public static readonly MAKEDATE = 230; + public static readonly MAKETIME = 231; + public static readonly MONTHNAME = 232; + public static readonly NOW = 233; + public static readonly PERIOD_ADD = 234; + public static readonly PERIOD_DIFF = 235; + public static readonly SEC_TO_TIME = 236; + public static readonly STR_TO_DATE = 237; + public static readonly SUBDATE = 238; + public static readonly SUBTIME = 239; + public static readonly SYSDATE = 240; + public static readonly TIME = 241; + public static readonly TIMEDIFF = 242; + public static readonly TIMESTAMP = 243; + public static readonly TIMESTAMPADD = 244; + public static readonly TIMESTAMPDIFF = 245; + public static readonly TIME_FORMAT = 246; + public static readonly TIME_TO_SEC = 247; + public static readonly TO_DAYS = 248; + public static readonly TO_SECONDS = 249; + public static readonly UNIX_TIMESTAMP = 250; + public static readonly UTC_DATE = 251; + public static readonly UTC_TIME = 252; + public static readonly UTC_TIMESTAMP = 253; + public static readonly WEEKDAY = 254; + public static readonly YEARWEEK = 255; + public static readonly SUBSTR = 256; + public static readonly SUBSTRING = 257; + public static readonly LTRIM = 258; + public static readonly RTRIM = 259; + public static readonly TRIM = 260; + public static readonly TO = 261; + public static readonly LOWER = 262; + public static readonly UPPER = 263; + public static readonly CONCAT = 264; + public static readonly CONCAT_WS = 265; + public static readonly LENGTH = 266; + public static readonly STRCMP = 267; + public static readonly RIGHT = 268; + public static readonly LEFT = 269; + public static readonly ASCII = 270; + public static readonly LOCATE = 271; + public static readonly REPLACE = 272; + public static readonly REVERSE = 273; + public static readonly CAST = 274; + public static readonly LIKE = 275; + public static readonly ISNULL = 276; + public static readonly ISNOTNULL = 277; + public static readonly IFNULL = 278; + public static readonly NULLIF = 279; + public static readonly IF = 280; + public static readonly TYPEOF = 281; + public static readonly MATCH = 282; + public static readonly MATCH_PHRASE = 283; + public static readonly MATCH_PHRASE_PREFIX = 284; + public static readonly MATCH_BOOL_PREFIX = 285; + public static readonly SIMPLE_QUERY_STRING = 286; + public static readonly MULTI_MATCH = 287; + public static readonly QUERY_STRING = 288; + public static readonly ALLOW_LEADING_WILDCARD = 289; + public static readonly ANALYZE_WILDCARD = 290; + public static readonly ANALYZER = 291; + public static readonly AUTO_GENERATE_SYNONYMS_PHRASE_QUERY = 292; + public static readonly BOOST = 293; + public static readonly CUTOFF_FREQUENCY = 294; + public static readonly DEFAULT_FIELD = 295; + public static readonly DEFAULT_OPERATOR = 296; + public static readonly ENABLE_POSITION_INCREMENTS = 297; + public static readonly ESCAPE = 298; + public static readonly FLAGS = 299; + public static readonly FUZZY_MAX_EXPANSIONS = 300; + public static readonly FUZZY_PREFIX_LENGTH = 301; + public static readonly FUZZY_TRANSPOSITIONS = 302; + public static readonly FUZZY_REWRITE = 303; + public static readonly FUZZINESS = 304; + public static readonly LENIENT = 305; + public static readonly LOW_FREQ_OPERATOR = 306; + public static readonly MAX_DETERMINIZED_STATES = 307; + public static readonly MAX_EXPANSIONS = 308; + public static readonly MINIMUM_SHOULD_MATCH = 309; + public static readonly OPERATOR = 310; + public static readonly PHRASE_SLOP = 311; + public static readonly PREFIX_LENGTH = 312; + public static readonly QUOTE_ANALYZER = 313; + public static readonly QUOTE_FIELD_SUFFIX = 314; + public static readonly REWRITE = 315; + public static readonly SLOP = 316; + public static readonly TIE_BREAKER = 317; + public static readonly TYPE = 318; + public static readonly ZERO_TERMS_QUERY = 319; + public static readonly SPAN = 320; + public static readonly MS = 321; + public static readonly S = 322; + public static readonly M = 323; + public static readonly H = 324; + public static readonly W = 325; + public static readonly Q = 326; + public static readonly Y = 327; + public static readonly ID = 328; + public static readonly CLUSTER = 329; + public static readonly INTEGER_LITERAL = 330; + public static readonly DECIMAL_LITERAL = 331; + public static readonly ID_DATE_SUFFIX = 332; + public static readonly DQUOTA_STRING = 333; + public static readonly SQUOTA_STRING = 334; + public static readonly BQUOTA_STRING = 335; + public static readonly ERROR_RECOGNITION = 336; + public static readonly RULE_root = 0; + public static readonly RULE_pplStatement = 1; + public static readonly RULE_dmlStatement = 2; + public static readonly RULE_queryStatement = 3; + public static readonly RULE_pplCommands = 4; + public static readonly RULE_commands = 5; + public static readonly RULE_searchCommand = 6; + public static readonly RULE_describeCommand = 7; + public static readonly RULE_showDataSourcesCommand = 8; + public static readonly RULE_whereCommand = 9; + public static readonly RULE_fieldsCommand = 10; + public static readonly RULE_renameCommand = 11; + public static readonly RULE_statsCommand = 12; + public static readonly RULE_dedupCommand = 13; + public static readonly RULE_sortCommand = 14; + public static readonly RULE_evalCommand = 15; + public static readonly RULE_headCommand = 16; + public static readonly RULE_topCommand = 17; + public static readonly RULE_rareCommand = 18; + public static readonly RULE_grokCommand = 19; + public static readonly RULE_parseCommand = 20; + public static readonly RULE_patternsCommand = 21; + public static readonly RULE_patternsParameter = 22; + public static readonly RULE_patternsMethod = 23; + public static readonly RULE_kmeansCommand = 24; + public static readonly RULE_kmeansParameter = 25; + public static readonly RULE_adCommand = 26; + public static readonly RULE_adParameter = 27; + public static readonly RULE_mlCommand = 28; + public static readonly RULE_mlArg = 29; + public static readonly RULE_fromClause = 30; + public static readonly RULE_tableSourceClause = 31; + public static readonly RULE_renameClasue = 32; + public static readonly RULE_byClause = 33; + public static readonly RULE_statsByClause = 34; + public static readonly RULE_bySpanClause = 35; + public static readonly RULE_spanClause = 36; + public static readonly RULE_sortbyClause = 37; + public static readonly RULE_evalClause = 38; + public static readonly RULE_statsAggTerm = 39; + public static readonly RULE_statsFunction = 40; + public static readonly RULE_statsFunctionName = 41; + public static readonly RULE_takeAggFunction = 42; + public static readonly RULE_percentileAggFunction = 43; + public static readonly RULE_expression = 44; + public static readonly RULE_logicalExpression = 45; + public static readonly RULE_comparisonExpression = 46; + public static readonly RULE_valueExpression = 47; + public static readonly RULE_primaryExpression = 48; + public static readonly RULE_positionFunction = 49; + public static readonly RULE_booleanExpression = 50; + public static readonly RULE_relevanceExpression = 51; + public static readonly RULE_singleFieldRelevanceFunction = 52; + public static readonly RULE_multiFieldRelevanceFunction = 53; + public static readonly RULE_tableSource = 54; + public static readonly RULE_tableFunction = 55; + public static readonly RULE_fieldList = 56; + public static readonly RULE_wcFieldList = 57; + public static readonly RULE_sortField = 58; + public static readonly RULE_sortFieldExpression = 59; + public static readonly RULE_fieldExpression = 60; + public static readonly RULE_wcFieldExpression = 61; + public static readonly RULE_evalFunctionCall = 62; + public static readonly RULE_dataTypeFunctionCall = 63; + public static readonly RULE_booleanFunctionCall = 64; + public static readonly RULE_convertedDataType = 65; + public static readonly RULE_evalFunctionName = 66; + public static readonly RULE_functionArgs = 67; + public static readonly RULE_functionArg = 68; + public static readonly RULE_relevanceArg = 69; + public static readonly RULE_relevanceArgName = 70; + public static readonly RULE_relevanceFieldAndWeight = 71; + public static readonly RULE_relevanceFieldWeight = 72; + public static readonly RULE_relevanceField = 73; + public static readonly RULE_relevanceQuery = 74; + public static readonly RULE_relevanceArgValue = 75; + public static readonly RULE_mathematicalFunctionName = 76; + public static readonly RULE_trigonometricFunctionName = 77; + public static readonly RULE_dateTimeFunctionName = 78; + public static readonly RULE_getFormatFunction = 79; + public static readonly RULE_getFormatType = 80; + public static readonly RULE_extractFunction = 81; + public static readonly RULE_simpleDateTimePart = 82; + public static readonly RULE_complexDateTimePart = 83; + public static readonly RULE_datetimePart = 84; + public static readonly RULE_timestampFunction = 85; + public static readonly RULE_timestampFunctionName = 86; + public static readonly RULE_conditionFunctionBase = 87; + public static readonly RULE_systemFunctionName = 88; + public static readonly RULE_textFunctionName = 89; + public static readonly RULE_positionFunctionName = 90; + public static readonly RULE_comparisonOperator = 91; + public static readonly RULE_singleFieldRelevanceFunctionName = 92; + public static readonly RULE_multiFieldRelevanceFunctionName = 93; + public static readonly RULE_literalValue = 94; + public static readonly RULE_intervalLiteral = 95; + public static readonly RULE_stringLiteral = 96; + public static readonly RULE_integerLiteral = 97; + public static readonly RULE_decimalLiteral = 98; + public static readonly RULE_booleanLiteral = 99; + public static readonly RULE_datetimeLiteral = 100; + public static readonly RULE_dateLiteral = 101; + public static readonly RULE_timeLiteral = 102; + public static readonly RULE_timestampLiteral = 103; + public static readonly RULE_intervalUnit = 104; + public static readonly RULE_timespanUnit = 105; + public static readonly RULE_valueList = 106; + public static readonly RULE_qualifiedName = 107; + public static readonly RULE_tableQualifiedName = 108; + public static readonly RULE_wcQualifiedName = 109; + public static readonly RULE_ident = 110; + public static readonly RULE_tableIdent = 111; + public static readonly RULE_wildcard = 112; + public static readonly RULE_keywordsCanBeId = 113; + + public static readonly literalNames = [ + null, null, "'SEARCH'", "'DESCRIBE'", "'SHOW'", "'FROM'", "'WHERE'", + "'FIELDS'", "'RENAME'", "'STATS'", "'DEDUP'", "'SORT'", "'EVAL'", + "'HEAD'", "'TOP'", "'RARE'", "'PARSE'", "'METHOD'", "'REGEX'", "'PUNCT'", + "'GROK'", "'PATTERN'", "'PATTERNS'", "'NEW_FIELD'", "'KMEANS'", + "'AD'", "'ML'", "'AS'", "'BY'", "'SOURCE'", "'INDEX'", "'D'", "'DESC'", + "'DATASOURCES'", "'SORTBY'", "'AUTO'", "'STR'", "'IP'", "'NUM'", + "'KEEPEMPTY'", "'CONSECUTIVE'", "'DEDUP_SPLITVALUES'", "'PARTITIONS'", + "'ALLNUM'", "'DELIM'", "'CENTROIDS'", "'ITERATIONS'", "'DISTANCE_TYPE'", + "'NUMBER_OF_TREES'", "'SHINGLE_SIZE'", "'SAMPLE_SIZE'", "'OUTPUT_AFTER'", + "'TIME_DECAY'", "'ANOMALY_RATE'", "'CATEGORY_FIELD'", "'TIME_FIELD'", + "'TIME_ZONE'", "'TRAINING_DATA_SIZE'", "'ANOMALY_SCORE_THRESHOLD'", + "'CASE'", "'IN'", "'NOT'", "'OR'", "'AND'", "'XOR'", "'TRUE'", "'FALSE'", + "'REGEXP'", "'CONVERT_TZ'", "'DATETIME'", "'DAY'", "'DAY_HOUR'", + "'DAY_MICROSECOND'", "'DAY_MINUTE'", "'DAY_OF_YEAR'", "'DAY_SECOND'", + "'HOUR'", "'HOUR_MICROSECOND'", "'HOUR_MINUTE'", "'HOUR_OF_DAY'", + "'HOUR_SECOND'", "'INTERVAL'", "'MICROSECOND'", "'MILLISECOND'", + "'MINUTE'", "'MINUTE_MICROSECOND'", "'MINUTE_OF_DAY'", "'MINUTE_OF_HOUR'", + "'MINUTE_SECOND'", "'MONTH'", "'MONTH_OF_YEAR'", "'QUARTER'", "'SECOND'", + "'SECOND_MICROSECOND'", "'SECOND_OF_MINUTE'", "'WEEK'", "'WEEK_OF_YEAR'", + "'YEAR'", "'YEAR_MONTH'", "'DATAMODEL'", "'LOOKUP'", "'SAVEDSEARCH'", + "'INT'", "'INTEGER'", "'DOUBLE'", "'LONG'", "'FLOAT'", "'STRING'", + "'BOOLEAN'", "'|'", "','", "'.'", "'='", "'>'", "'<'", null, null, + null, "'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "':'", "'('", "')'", + "'['", "']'", "'''", "'\"'", "'`'", "'~'", "'&'", "'^'", "'AVG'", + "'COUNT'", "'DISTINCT_COUNT'", "'ESTDC'", "'ESTDC_ERROR'", "'MAX'", + "'MEAN'", "'MEDIAN'", "'MIN'", "'MODE'", "'RANGE'", "'STDEV'", "'STDEVP'", + "'SUM'", "'SUMSQ'", "'VAR_SAMP'", "'VAR_POP'", "'STDDEV_SAMP'", + "'STDDEV_POP'", "'PERCENTILE'", "'TAKE'", "'FIRST'", "'LAST'", "'LIST'", + "'VALUES'", "'EARLIEST'", "'EARLIEST_TIME'", "'LATEST'", "'LATEST_TIME'", + "'PER_DAY'", "'PER_HOUR'", "'PER_MINUTE'", "'PER_SECOND'", "'RATE'", + "'SPARKLINE'", "'C'", "'DC'", "'ABS'", "'CBRT'", "'CEIL'", "'CEILING'", + "'CONV'", "'CRC32'", "'E'", "'EXP'", "'FLOOR'", "'LN'", "'LOG'", + "'LOG10'", "'LOG2'", "'MOD'", "'PI'", "'POSITION'", "'POW'", "'POWER'", + "'RAND'", "'ROUND'", "'SIGN'", "'SQRT'", "'TRUNCATE'", "'ACOS'", + "'ASIN'", "'ATAN'", "'ATAN2'", "'COS'", "'COT'", "'DEGREES'", "'RADIANS'", + "'SIN'", "'TAN'", "'ADDDATE'", "'ADDTIME'", "'CURDATE'", "'CURRENT_DATE'", + "'CURRENT_TIME'", "'CURRENT_TIMESTAMP'", "'CURTIME'", "'DATE'", + "'DATEDIFF'", "'DATE_ADD'", "'DATE_FORMAT'", "'DATE_SUB'", "'DAYNAME'", + "'DAYOFMONTH'", "'DAYOFWEEK'", "'DAYOFYEAR'", "'DAY_OF_MONTH'", + "'DAY_OF_WEEK'", "'EXTRACT'", "'FROM_DAYS'", "'FROM_UNIXTIME'", + "'GET_FORMAT'", "'LAST_DAY'", "'LOCALTIME'", "'LOCALTIMESTAMP'", + "'MAKEDATE'", "'MAKETIME'", "'MONTHNAME'", "'NOW'", "'PERIOD_ADD'", + "'PERIOD_DIFF'", "'SEC_TO_TIME'", "'STR_TO_DATE'", "'SUBDATE'", + "'SUBTIME'", "'SYSDATE'", "'TIME'", "'TIMEDIFF'", "'TIMESTAMP'", + "'TIMESTAMPADD'", "'TIMESTAMPDIFF'", "'TIME_FORMAT'", "'TIME_TO_SEC'", + "'TO_DAYS'", "'TO_SECONDS'", "'UNIX_TIMESTAMP'", "'UTC_DATE'", "'UTC_TIME'", + "'UTC_TIMESTAMP'", "'WEEKDAY'", "'YEARWEEK'", "'SUBSTR'", "'SUBSTRING'", + "'LTRIM'", "'RTRIM'", "'TRIM'", "'TO'", "'LOWER'", "'UPPER'", "'CONCAT'", + "'CONCAT_WS'", "'LENGTH'", "'STRCMP'", "'RIGHT'", "'LEFT'", "'ASCII'", + "'LOCATE'", "'REPLACE'", "'REVERSE'", "'CAST'", "'LIKE'", "'ISNULL'", + "'ISNOTNULL'", "'IFNULL'", "'NULLIF'", "'IF'", "'TYPEOF'", "'MATCH'", + "'MATCH_PHRASE'", "'MATCH_PHRASE_PREFIX'", "'MATCH_BOOL_PREFIX'", + "'SIMPLE_QUERY_STRING'", "'MULTI_MATCH'", "'QUERY_STRING'", "'ALLOW_LEADING_WILDCARD'", + "'ANALYZE_WILDCARD'", "'ANALYZER'", "'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY'", + "'BOOST'", "'CUTOFF_FREQUENCY'", "'DEFAULT_FIELD'", "'DEFAULT_OPERATOR'", + "'ENABLE_POSITION_INCREMENTS'", "'ESCAPE'", "'FLAGS'", "'FUZZY_MAX_EXPANSIONS'", + "'FUZZY_PREFIX_LENGTH'", "'FUZZY_TRANSPOSITIONS'", "'FUZZY_REWRITE'", + "'FUZZINESS'", "'LENIENT'", "'LOW_FREQ_OPERATOR'", "'MAX_DETERMINIZED_STATES'", + "'MAX_EXPANSIONS'", "'MINIMUM_SHOULD_MATCH'", "'OPERATOR'", "'PHRASE_SLOP'", + "'PREFIX_LENGTH'", "'QUOTE_ANALYZER'", "'QUOTE_FIELD_SUFFIX'", "'REWRITE'", + "'SLOP'", "'TIE_BREAKER'", "'TYPE'", "'ZERO_TERMS_QUERY'", "'SPAN'", + "'MS'", "'S'", "'M'", "'H'", "'W'", "'Q'", "'Y'" + ]; + + public static readonly symbolicNames = [ + null, "SPACE", "SEARCH", "DESCRIBE", "SHOW", "FROM", "WHERE", "FIELDS", + "RENAME", "STATS", "DEDUP", "SORT", "EVAL", "HEAD", "TOP", "RARE", + "PARSE", "METHOD", "REGEX", "PUNCT", "GROK", "PATTERN", "PATTERNS", + "NEW_FIELD", "KMEANS", "AD", "ML", "AS", "BY", "SOURCE", "INDEX", + "D", "DESC", "DATASOURCES", "SORTBY", "AUTO", "STR", "IP", "NUM", + "KEEPEMPTY", "CONSECUTIVE", "DEDUP_SPLITVALUES", "PARTITIONS", "ALLNUM", + "DELIM", "CENTROIDS", "ITERATIONS", "DISTANCE_TYPE", "NUMBER_OF_TREES", + "SHINGLE_SIZE", "SAMPLE_SIZE", "OUTPUT_AFTER", "TIME_DECAY", "ANOMALY_RATE", + "CATEGORY_FIELD", "TIME_FIELD", "TIME_ZONE", "TRAINING_DATA_SIZE", + "ANOMALY_SCORE_THRESHOLD", "CASE", "IN", "NOT", "OR", "AND", "XOR", + "TRUE", "FALSE", "REGEXP", "CONVERT_TZ", "DATETIME", "DAY", "DAY_HOUR", + "DAY_MICROSECOND", "DAY_MINUTE", "DAY_OF_YEAR", "DAY_SECOND", "HOUR", + "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_OF_DAY", "HOUR_SECOND", + "INTERVAL", "MICROSECOND", "MILLISECOND", "MINUTE", "MINUTE_MICROSECOND", + "MINUTE_OF_DAY", "MINUTE_OF_HOUR", "MINUTE_SECOND", "MONTH", "MONTH_OF_YEAR", + "QUARTER", "SECOND", "SECOND_MICROSECOND", "SECOND_OF_MINUTE", "WEEK", + "WEEK_OF_YEAR", "YEAR", "YEAR_MONTH", "DATAMODEL", "LOOKUP", "SAVEDSEARCH", + "INT", "INTEGER", "DOUBLE", "LONG", "FLOAT", "STRING", "BOOLEAN", + "PIPE", "COMMA", "DOT", "EQUAL", "GREATER", "LESS", "NOT_GREATER", + "NOT_LESS", "NOT_EQUAL", "PLUS", "MINUS", "STAR", "DIVIDE", "MODULE", + "EXCLAMATION_SYMBOL", "COLON", "LT_PRTHS", "RT_PRTHS", "LT_SQR_PRTHS", + "RT_SQR_PRTHS", "SINGLE_QUOTE", "DOUBLE_QUOTE", "BACKTICK", "BIT_NOT_OP", + "BIT_AND_OP", "BIT_XOR_OP", "AVG", "COUNT", "DISTINCT_COUNT", "ESTDC", + "ESTDC_ERROR", "MAX", "MEAN", "MEDIAN", "MIN", "MODE", "RANGE", + "STDEV", "STDEVP", "SUM", "SUMSQ", "VAR_SAMP", "VAR_POP", "STDDEV_SAMP", + "STDDEV_POP", "PERCENTILE", "TAKE", "FIRST", "LAST", "LIST", "VALUES", + "EARLIEST", "EARLIEST_TIME", "LATEST", "LATEST_TIME", "PER_DAY", + "PER_HOUR", "PER_MINUTE", "PER_SECOND", "RATE", "SPARKLINE", "C", + "DC", "ABS", "CBRT", "CEIL", "CEILING", "CONV", "CRC32", "E", "EXP", + "FLOOR", "LN", "LOG", "LOG10", "LOG2", "MOD", "PI", "POSITION", + "POW", "POWER", "RAND", "ROUND", "SIGN", "SQRT", "TRUNCATE", "ACOS", + "ASIN", "ATAN", "ATAN2", "COS", "COT", "DEGREES", "RADIANS", "SIN", + "TAN", "ADDDATE", "ADDTIME", "CURDATE", "CURRENT_DATE", "CURRENT_TIME", + "CURRENT_TIMESTAMP", "CURTIME", "DATE", "DATEDIFF", "DATE_ADD", + "DATE_FORMAT", "DATE_SUB", "DAYNAME", "DAYOFMONTH", "DAYOFWEEK", + "DAYOFYEAR", "DAY_OF_MONTH", "DAY_OF_WEEK", "EXTRACT", "FROM_DAYS", + "FROM_UNIXTIME", "GET_FORMAT", "LAST_DAY", "LOCALTIME", "LOCALTIMESTAMP", + "MAKEDATE", "MAKETIME", "MONTHNAME", "NOW", "PERIOD_ADD", "PERIOD_DIFF", + "SEC_TO_TIME", "STR_TO_DATE", "SUBDATE", "SUBTIME", "SYSDATE", "TIME", + "TIMEDIFF", "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", "TIME_FORMAT", + "TIME_TO_SEC", "TO_DAYS", "TO_SECONDS", "UNIX_TIMESTAMP", "UTC_DATE", + "UTC_TIME", "UTC_TIMESTAMP", "WEEKDAY", "YEARWEEK", "SUBSTR", "SUBSTRING", + "LTRIM", "RTRIM", "TRIM", "TO", "LOWER", "UPPER", "CONCAT", "CONCAT_WS", + "LENGTH", "STRCMP", "RIGHT", "LEFT", "ASCII", "LOCATE", "REPLACE", + "REVERSE", "CAST", "LIKE", "ISNULL", "ISNOTNULL", "IFNULL", "NULLIF", + "IF", "TYPEOF", "MATCH", "MATCH_PHRASE", "MATCH_PHRASE_PREFIX", + "MATCH_BOOL_PREFIX", "SIMPLE_QUERY_STRING", "MULTI_MATCH", "QUERY_STRING", + "ALLOW_LEADING_WILDCARD", "ANALYZE_WILDCARD", "ANALYZER", "AUTO_GENERATE_SYNONYMS_PHRASE_QUERY", + "BOOST", "CUTOFF_FREQUENCY", "DEFAULT_FIELD", "DEFAULT_OPERATOR", + "ENABLE_POSITION_INCREMENTS", "ESCAPE", "FLAGS", "FUZZY_MAX_EXPANSIONS", + "FUZZY_PREFIX_LENGTH", "FUZZY_TRANSPOSITIONS", "FUZZY_REWRITE", + "FUZZINESS", "LENIENT", "LOW_FREQ_OPERATOR", "MAX_DETERMINIZED_STATES", + "MAX_EXPANSIONS", "MINIMUM_SHOULD_MATCH", "OPERATOR", "PHRASE_SLOP", + "PREFIX_LENGTH", "QUOTE_ANALYZER", "QUOTE_FIELD_SUFFIX", "REWRITE", + "SLOP", "TIE_BREAKER", "TYPE", "ZERO_TERMS_QUERY", "SPAN", "MS", + "S", "M", "H", "W", "Q", "Y", "ID", "CLUSTER", "INTEGER_LITERAL", + "DECIMAL_LITERAL", "ID_DATE_SUFFIX", "DQUOTA_STRING", "SQUOTA_STRING", + "BQUOTA_STRING", "ERROR_RECOGNITION" + ]; + public static readonly ruleNames = [ + "root", "pplStatement", "dmlStatement", "queryStatement", "pplCommands", + "commands", "searchCommand", "describeCommand", "showDataSourcesCommand", + "whereCommand", "fieldsCommand", "renameCommand", "statsCommand", + "dedupCommand", "sortCommand", "evalCommand", "headCommand", "topCommand", + "rareCommand", "grokCommand", "parseCommand", "patternsCommand", + "patternsParameter", "patternsMethod", "kmeansCommand", "kmeansParameter", + "adCommand", "adParameter", "mlCommand", "mlArg", "fromClause", + "tableSourceClause", "renameClasue", "byClause", "statsByClause", + "bySpanClause", "spanClause", "sortbyClause", "evalClause", "statsAggTerm", + "statsFunction", "statsFunctionName", "takeAggFunction", "percentileAggFunction", + "expression", "logicalExpression", "comparisonExpression", "valueExpression", + "primaryExpression", "positionFunction", "booleanExpression", "relevanceExpression", + "singleFieldRelevanceFunction", "multiFieldRelevanceFunction", "tableSource", + "tableFunction", "fieldList", "wcFieldList", "sortField", "sortFieldExpression", + "fieldExpression", "wcFieldExpression", "evalFunctionCall", "dataTypeFunctionCall", + "booleanFunctionCall", "convertedDataType", "evalFunctionName", + "functionArgs", "functionArg", "relevanceArg", "relevanceArgName", + "relevanceFieldAndWeight", "relevanceFieldWeight", "relevanceField", + "relevanceQuery", "relevanceArgValue", "mathematicalFunctionName", + "trigonometricFunctionName", "dateTimeFunctionName", "getFormatFunction", + "getFormatType", "extractFunction", "simpleDateTimePart", "complexDateTimePart", + "datetimePart", "timestampFunction", "timestampFunctionName", "conditionFunctionBase", + "systemFunctionName", "textFunctionName", "positionFunctionName", + "comparisonOperator", "singleFieldRelevanceFunctionName", "multiFieldRelevanceFunctionName", + "literalValue", "intervalLiteral", "stringLiteral", "integerLiteral", + "decimalLiteral", "booleanLiteral", "datetimeLiteral", "dateLiteral", + "timeLiteral", "timestampLiteral", "intervalUnit", "timespanUnit", + "valueList", "qualifiedName", "tableQualifiedName", "wcQualifiedName", + "ident", "tableIdent", "wildcard", "keywordsCanBeId", + ]; + + public get grammarFileName(): string { return "OpenSearchPPLParser.g4"; } + public get literalNames(): (string | null)[] { return OpenSearchPPLParser.literalNames; } + public get symbolicNames(): (string | null)[] { return OpenSearchPPLParser.symbolicNames; } + public get ruleNames(): string[] { return OpenSearchPPLParser.ruleNames; } + public get serializedATN(): number[] { return OpenSearchPPLParser._serializedATN; } + + protected createFailedPredicateException(predicate?: string, message?: string): antlr.FailedPredicateException { + return new antlr.FailedPredicateException(this, predicate, message); + } + + public constructor(input: antlr.TokenStream) { + super(input); + this.interpreter = new antlr.ParserATNSimulator(this, OpenSearchPPLParser._ATN, OpenSearchPPLParser.decisionsToDFA, new antlr.PredictionContextCache()); + } + public root(): RootContext { + let localContext = new RootContext(this.context, this.state); + this.enterRule(localContext, 0, OpenSearchPPLParser.RULE_root); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 229; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if ((((_la) & ~0x1F) === 0 && ((1 << _la) & 3892314108) !== 0) || ((((_la - 32)) & ~0x1F) === 0 && ((1 << (_la - 32)) & 671088631) !== 0) || ((((_la - 65)) & ~0x1F) === 0 && ((1 << (_la - 65)) & 4294967291) !== 0) || ((((_la - 97)) & ~0x1F) === 0 && ((1 << (_la - 97)) & 274743299) !== 0) || ((((_la - 131)) & ~0x1F) === 0 && ((1 << (_la - 131)) & 4294967281) !== 0) || ((((_la - 163)) & ~0x1F) === 0 && ((1 << (_la - 163)) & 4294967295) !== 0) || ((((_la - 195)) & ~0x1F) === 0 && ((1 << (_la - 195)) & 4294967295) !== 0) || ((((_la - 227)) & ~0x1F) === 0 && ((1 << (_la - 227)) & 4294967295) !== 0) || ((((_la - 259)) & ~0x1F) === 0 && ((1 << (_la - 259)) & 4294967291) !== 0) || ((((_la - 291)) & ~0x1F) === 0 && ((1 << (_la - 291)) & 4294967295) !== 0) || ((((_la - 323)) & ~0x1F) === 0 && ((1 << (_la - 323)) & 7615) !== 0)) { + { + this.state = 228; + this.pplStatement(); + } + } + + this.state = 231; + this.match(OpenSearchPPLParser.EOF); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public pplStatement(): PplStatementContext { + let localContext = new PplStatementContext(this.context, this.state); + this.enterRule(localContext, 2, OpenSearchPPLParser.RULE_pplStatement); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 233; + this.dmlStatement(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public dmlStatement(): DmlStatementContext { + let localContext = new DmlStatementContext(this.context, this.state); + this.enterRule(localContext, 4, OpenSearchPPLParser.RULE_dmlStatement); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 235; + this.queryStatement(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public queryStatement(): QueryStatementContext { + let localContext = new QueryStatementContext(this.context, this.state); + this.enterRule(localContext, 6, OpenSearchPPLParser.RULE_queryStatement); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 237; + this.pplCommands(); + this.state = 242; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 109) { + { + { + this.state = 238; + this.match(OpenSearchPPLParser.PIPE); + this.state = 239; + this.commands(); + } + } + this.state = 244; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public pplCommands(): PplCommandsContext { + let localContext = new PplCommandsContext(this.context, this.state); + this.enterRule(localContext, 8, OpenSearchPPLParser.RULE_pplCommands); + try { + this.state = 248; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 2, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 245; + this.searchCommand(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 246; + this.describeCommand(); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 247; + this.showDataSourcesCommand(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public commands(): CommandsContext { + let localContext = new CommandsContext(this.context, this.state); + this.enterRule(localContext, 10, OpenSearchPPLParser.RULE_commands); + try { + this.state = 266; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.WHERE: + this.enterOuterAlt(localContext, 1); + { + this.state = 250; + this.whereCommand(); + } + break; + case OpenSearchPPLParser.FIELDS: + this.enterOuterAlt(localContext, 2); + { + this.state = 251; + this.fieldsCommand(); + } + break; + case OpenSearchPPLParser.RENAME: + this.enterOuterAlt(localContext, 3); + { + this.state = 252; + this.renameCommand(); + } + break; + case OpenSearchPPLParser.STATS: + this.enterOuterAlt(localContext, 4); + { + this.state = 253; + this.statsCommand(); + } + break; + case OpenSearchPPLParser.DEDUP: + this.enterOuterAlt(localContext, 5); + { + this.state = 254; + this.dedupCommand(); + } + break; + case OpenSearchPPLParser.SORT: + this.enterOuterAlt(localContext, 6); + { + this.state = 255; + this.sortCommand(); + } + break; + case OpenSearchPPLParser.EVAL: + this.enterOuterAlt(localContext, 7); + { + this.state = 256; + this.evalCommand(); + } + break; + case OpenSearchPPLParser.HEAD: + this.enterOuterAlt(localContext, 8); + { + this.state = 257; + this.headCommand(); + } + break; + case OpenSearchPPLParser.TOP: + this.enterOuterAlt(localContext, 9); + { + this.state = 258; + this.topCommand(); + } + break; + case OpenSearchPPLParser.RARE: + this.enterOuterAlt(localContext, 10); + { + this.state = 259; + this.rareCommand(); + } + break; + case OpenSearchPPLParser.GROK: + this.enterOuterAlt(localContext, 11); + { + this.state = 260; + this.grokCommand(); + } + break; + case OpenSearchPPLParser.PARSE: + this.enterOuterAlt(localContext, 12); + { + this.state = 261; + this.parseCommand(); + } + break; + case OpenSearchPPLParser.PATTERNS: + this.enterOuterAlt(localContext, 13); + { + this.state = 262; + this.patternsCommand(); + } + break; + case OpenSearchPPLParser.KMEANS: + this.enterOuterAlt(localContext, 14); + { + this.state = 263; + this.kmeansCommand(); + } + break; + case OpenSearchPPLParser.AD: + this.enterOuterAlt(localContext, 15); + { + this.state = 264; + this.adCommand(); + } + break; + case OpenSearchPPLParser.ML: + this.enterOuterAlt(localContext, 16); + { + this.state = 265; + this.mlCommand(); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public searchCommand(): SearchCommandContext { + let localContext = new SearchCommandContext(this.context, this.state); + this.enterRule(localContext, 12, OpenSearchPPLParser.RULE_searchCommand); + let _la: number; + try { + this.state = 284; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 7, this.context) ) { + case 1: + localContext = new SearchFromContext(localContext); + this.enterOuterAlt(localContext, 1); + { + this.state = 269; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 2) { + { + this.state = 268; + this.match(OpenSearchPPLParser.SEARCH); + } + } + + this.state = 271; + this.fromClause(); + } + break; + case 2: + localContext = new SearchFromFilterContext(localContext); + this.enterOuterAlt(localContext, 2); + { + this.state = 273; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 2) { + { + this.state = 272; + this.match(OpenSearchPPLParser.SEARCH); + } + } + + this.state = 275; + this.fromClause(); + this.state = 276; + this.logicalExpression(0); + } + break; + case 3: + localContext = new SearchFilterFromContext(localContext); + this.enterOuterAlt(localContext, 3); + { + this.state = 279; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 6, this.context) ) { + case 1: + { + this.state = 278; + this.match(OpenSearchPPLParser.SEARCH); + } + break; + } + this.state = 281; + this.logicalExpression(0); + this.state = 282; + this.fromClause(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public describeCommand(): DescribeCommandContext { + let localContext = new DescribeCommandContext(this.context, this.state); + this.enterRule(localContext, 14, OpenSearchPPLParser.RULE_describeCommand); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 286; + this.match(OpenSearchPPLParser.DESCRIBE); + this.state = 287; + this.tableSourceClause(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public showDataSourcesCommand(): ShowDataSourcesCommandContext { + let localContext = new ShowDataSourcesCommandContext(this.context, this.state); + this.enterRule(localContext, 16, OpenSearchPPLParser.RULE_showDataSourcesCommand); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 289; + this.match(OpenSearchPPLParser.SHOW); + this.state = 290; + this.match(OpenSearchPPLParser.DATASOURCES); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public whereCommand(): WhereCommandContext { + let localContext = new WhereCommandContext(this.context, this.state); + this.enterRule(localContext, 18, OpenSearchPPLParser.RULE_whereCommand); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 292; + this.match(OpenSearchPPLParser.WHERE); + this.state = 293; + this.logicalExpression(0); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public fieldsCommand(): FieldsCommandContext { + let localContext = new FieldsCommandContext(this.context, this.state); + this.enterRule(localContext, 20, OpenSearchPPLParser.RULE_fieldsCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 295; + this.match(OpenSearchPPLParser.FIELDS); + this.state = 297; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 118 || _la === 119) { + { + this.state = 296; + _la = this.tokenStream.LA(1); + if(!(_la === 118 || _la === 119)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + + this.state = 299; + this.fieldList(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public renameCommand(): RenameCommandContext { + let localContext = new RenameCommandContext(this.context, this.state); + this.enterRule(localContext, 22, OpenSearchPPLParser.RULE_renameCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 301; + this.match(OpenSearchPPLParser.RENAME); + this.state = 302; + this.renameClasue(); + this.state = 307; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 303; + this.match(OpenSearchPPLParser.COMMA); + this.state = 304; + this.renameClasue(); + } + } + this.state = 309; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public statsCommand(): StatsCommandContext { + let localContext = new StatsCommandContext(this.context, this.state); + this.enterRule(localContext, 24, OpenSearchPPLParser.RULE_statsCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 310; + this.match(OpenSearchPPLParser.STATS); + this.state = 314; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 42) { + { + this.state = 311; + this.match(OpenSearchPPLParser.PARTITIONS); + this.state = 312; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 313; + localContext._partitions = this.integerLiteral(); + } + } + + this.state = 319; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 43) { + { + this.state = 316; + this.match(OpenSearchPPLParser.ALLNUM); + this.state = 317; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 318; + localContext._allnum = this.booleanLiteral(); + } + } + + this.state = 324; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 44) { + { + this.state = 321; + this.match(OpenSearchPPLParser.DELIM); + this.state = 322; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 323; + localContext._delim = this.stringLiteral(); + } + } + + this.state = 326; + this.statsAggTerm(); + this.state = 331; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 327; + this.match(OpenSearchPPLParser.COMMA); + this.state = 328; + this.statsAggTerm(); + } + } + this.state = 333; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + this.state = 335; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 28) { + { + this.state = 334; + this.statsByClause(); + } + } + + this.state = 340; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 41) { + { + this.state = 337; + this.match(OpenSearchPPLParser.DEDUP_SPLITVALUES); + this.state = 338; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 339; + localContext._dedupsplit = this.booleanLiteral(); + } + } + + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public dedupCommand(): DedupCommandContext { + let localContext = new DedupCommandContext(this.context, this.state); + this.enterRule(localContext, 26, OpenSearchPPLParser.RULE_dedupCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 342; + this.match(OpenSearchPPLParser.DEDUP); + this.state = 344; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 118 || _la === 119 || _la === 330) { + { + this.state = 343; + localContext._number_ = this.integerLiteral(); + } + } + + this.state = 346; + this.fieldList(); + this.state = 350; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 39) { + { + this.state = 347; + this.match(OpenSearchPPLParser.KEEPEMPTY); + this.state = 348; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 349; + localContext._keepempty = this.booleanLiteral(); + } + } + + this.state = 355; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 40) { + { + this.state = 352; + this.match(OpenSearchPPLParser.CONSECUTIVE); + this.state = 353; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 354; + localContext._consecutive = this.booleanLiteral(); + } + } + + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public sortCommand(): SortCommandContext { + let localContext = new SortCommandContext(this.context, this.state); + this.enterRule(localContext, 28, OpenSearchPPLParser.RULE_sortCommand); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 357; + this.match(OpenSearchPPLParser.SORT); + this.state = 358; + this.sortbyClause(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public evalCommand(): EvalCommandContext { + let localContext = new EvalCommandContext(this.context, this.state); + this.enterRule(localContext, 30, OpenSearchPPLParser.RULE_evalCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 360; + this.match(OpenSearchPPLParser.EVAL); + this.state = 361; + this.evalClause(); + this.state = 366; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 362; + this.match(OpenSearchPPLParser.COMMA); + this.state = 363; + this.evalClause(); + } + } + this.state = 368; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public headCommand(): HeadCommandContext { + let localContext = new HeadCommandContext(this.context, this.state); + this.enterRule(localContext, 32, OpenSearchPPLParser.RULE_headCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 369; + this.match(OpenSearchPPLParser.HEAD); + this.state = 371; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 118 || _la === 119 || _la === 330) { + { + this.state = 370; + localContext._number_ = this.integerLiteral(); + } + } + + this.state = 375; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 5) { + { + this.state = 373; + this.match(OpenSearchPPLParser.FROM); + this.state = 374; + localContext._from_ = this.integerLiteral(); + } + } + + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public topCommand(): TopCommandContext { + let localContext = new TopCommandContext(this.context, this.state); + this.enterRule(localContext, 34, OpenSearchPPLParser.RULE_topCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 377; + this.match(OpenSearchPPLParser.TOP); + this.state = 379; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 118 || _la === 119 || _la === 330) { + { + this.state = 378; + localContext._number_ = this.integerLiteral(); + } + } + + this.state = 381; + this.fieldList(); + this.state = 383; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 28) { + { + this.state = 382; + this.byClause(); + } + } + + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public rareCommand(): RareCommandContext { + let localContext = new RareCommandContext(this.context, this.state); + this.enterRule(localContext, 36, OpenSearchPPLParser.RULE_rareCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 385; + this.match(OpenSearchPPLParser.RARE); + this.state = 386; + this.fieldList(); + this.state = 388; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 28) { + { + this.state = 387; + this.byClause(); + } + } + + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public grokCommand(): GrokCommandContext { + let localContext = new GrokCommandContext(this.context, this.state); + this.enterRule(localContext, 38, OpenSearchPPLParser.RULE_grokCommand); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 390; + this.match(OpenSearchPPLParser.GROK); + { + this.state = 391; + localContext._source_field = this.expression(); + } + { + this.state = 392; + localContext._pattern = this.stringLiteral(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public parseCommand(): ParseCommandContext { + let localContext = new ParseCommandContext(this.context, this.state); + this.enterRule(localContext, 40, OpenSearchPPLParser.RULE_parseCommand); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 394; + this.match(OpenSearchPPLParser.PARSE); + { + this.state = 395; + localContext._source_field = this.expression(); + } + { + this.state = 396; + localContext._pattern = this.stringLiteral(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public patternsCommand(): PatternsCommandContext { + let localContext = new PatternsCommandContext(this.context, this.state); + this.enterRule(localContext, 42, OpenSearchPPLParser.RULE_patternsCommand); + try { + let alternative: number; + this.enterOuterAlt(localContext, 1); + { + this.state = 398; + this.match(OpenSearchPPLParser.PATTERNS); + this.state = 402; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 25, this.context); + while (alternative !== 2 && alternative !== antlr.ATN.INVALID_ALT_NUMBER) { + if (alternative === 1) { + { + { + this.state = 399; + this.patternsParameter(); + } + } + } + this.state = 404; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 25, this.context); + } + { + this.state = 405; + localContext._source_field = this.expression(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public patternsParameter(): PatternsParameterContext { + let localContext = new PatternsParameterContext(this.context, this.state); + this.enterRule(localContext, 44, OpenSearchPPLParser.RULE_patternsParameter); + try { + this.state = 413; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.NEW_FIELD: + this.enterOuterAlt(localContext, 1); + { + { + this.state = 407; + this.match(OpenSearchPPLParser.NEW_FIELD); + this.state = 408; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 409; + localContext._new_field = this.stringLiteral(); + } + } + break; + case OpenSearchPPLParser.PATTERN: + this.enterOuterAlt(localContext, 2); + { + { + this.state = 410; + this.match(OpenSearchPPLParser.PATTERN); + this.state = 411; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 412; + localContext._pattern = this.stringLiteral(); + } + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public patternsMethod(): PatternsMethodContext { + let localContext = new PatternsMethodContext(this.context, this.state); + this.enterRule(localContext, 46, OpenSearchPPLParser.RULE_patternsMethod); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 415; + _la = this.tokenStream.LA(1); + if(!(_la === 18 || _la === 19)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public kmeansCommand(): KmeansCommandContext { + let localContext = new KmeansCommandContext(this.context, this.state); + this.enterRule(localContext, 48, OpenSearchPPLParser.RULE_kmeansCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 417; + this.match(OpenSearchPPLParser.KMEANS); + this.state = 421; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (((((_la - 45)) & ~0x1F) === 0 && ((1 << (_la - 45)) & 7) !== 0)) { + { + { + this.state = 418; + this.kmeansParameter(); + } + } + this.state = 423; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public kmeansParameter(): KmeansParameterContext { + let localContext = new KmeansParameterContext(this.context, this.state); + this.enterRule(localContext, 50, OpenSearchPPLParser.RULE_kmeansParameter); + try { + this.state = 433; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.CENTROIDS: + this.enterOuterAlt(localContext, 1); + { + { + this.state = 424; + this.match(OpenSearchPPLParser.CENTROIDS); + this.state = 425; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 426; + localContext._centroids = this.integerLiteral(); + } + } + break; + case OpenSearchPPLParser.ITERATIONS: + this.enterOuterAlt(localContext, 2); + { + { + this.state = 427; + this.match(OpenSearchPPLParser.ITERATIONS); + this.state = 428; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 429; + localContext._iterations = this.integerLiteral(); + } + } + break; + case OpenSearchPPLParser.DISTANCE_TYPE: + this.enterOuterAlt(localContext, 3); + { + { + this.state = 430; + this.match(OpenSearchPPLParser.DISTANCE_TYPE); + this.state = 431; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 432; + localContext._distance_type = this.stringLiteral(); + } + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public adCommand(): AdCommandContext { + let localContext = new AdCommandContext(this.context, this.state); + this.enterRule(localContext, 52, OpenSearchPPLParser.RULE_adCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 435; + this.match(OpenSearchPPLParser.AD); + this.state = 439; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (((((_la - 48)) & ~0x1F) === 0 && ((1 << (_la - 48)) & 2047) !== 0) || _la === 215) { + { + { + this.state = 436; + this.adParameter(); + } + } + this.state = 441; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public adParameter(): AdParameterContext { + let localContext = new AdParameterContext(this.context, this.state); + this.enterRule(localContext, 54, OpenSearchPPLParser.RULE_adParameter); + try { + this.state = 478; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.NUMBER_OF_TREES: + this.enterOuterAlt(localContext, 1); + { + { + this.state = 442; + this.match(OpenSearchPPLParser.NUMBER_OF_TREES); + this.state = 443; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 444; + localContext._number_of_trees = this.integerLiteral(); + } + } + break; + case OpenSearchPPLParser.SHINGLE_SIZE: + this.enterOuterAlt(localContext, 2); + { + { + this.state = 445; + this.match(OpenSearchPPLParser.SHINGLE_SIZE); + this.state = 446; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 447; + localContext._shingle_size = this.integerLiteral(); + } + } + break; + case OpenSearchPPLParser.SAMPLE_SIZE: + this.enterOuterAlt(localContext, 3); + { + { + this.state = 448; + this.match(OpenSearchPPLParser.SAMPLE_SIZE); + this.state = 449; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 450; + localContext._sample_size = this.integerLiteral(); + } + } + break; + case OpenSearchPPLParser.OUTPUT_AFTER: + this.enterOuterAlt(localContext, 4); + { + { + this.state = 451; + this.match(OpenSearchPPLParser.OUTPUT_AFTER); + this.state = 452; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 453; + localContext._output_after = this.integerLiteral(); + } + } + break; + case OpenSearchPPLParser.TIME_DECAY: + this.enterOuterAlt(localContext, 5); + { + { + this.state = 454; + this.match(OpenSearchPPLParser.TIME_DECAY); + this.state = 455; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 456; + localContext._time_decay = this.decimalLiteral(); + } + } + break; + case OpenSearchPPLParser.ANOMALY_RATE: + this.enterOuterAlt(localContext, 6); + { + { + this.state = 457; + this.match(OpenSearchPPLParser.ANOMALY_RATE); + this.state = 458; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 459; + localContext._anomaly_rate = this.decimalLiteral(); + } + } + break; + case OpenSearchPPLParser.CATEGORY_FIELD: + this.enterOuterAlt(localContext, 7); + { + { + this.state = 460; + this.match(OpenSearchPPLParser.CATEGORY_FIELD); + this.state = 461; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 462; + localContext._category_field = this.stringLiteral(); + } + } + break; + case OpenSearchPPLParser.TIME_FIELD: + this.enterOuterAlt(localContext, 8); + { + { + this.state = 463; + this.match(OpenSearchPPLParser.TIME_FIELD); + this.state = 464; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 465; + localContext._time_field = this.stringLiteral(); + } + } + break; + case OpenSearchPPLParser.DATE_FORMAT: + this.enterOuterAlt(localContext, 9); + { + { + this.state = 466; + this.match(OpenSearchPPLParser.DATE_FORMAT); + this.state = 467; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 468; + localContext._date_format = this.stringLiteral(); + } + } + break; + case OpenSearchPPLParser.TIME_ZONE: + this.enterOuterAlt(localContext, 10); + { + { + this.state = 469; + this.match(OpenSearchPPLParser.TIME_ZONE); + this.state = 470; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 471; + localContext._time_zone = this.stringLiteral(); + } + } + break; + case OpenSearchPPLParser.TRAINING_DATA_SIZE: + this.enterOuterAlt(localContext, 11); + { + { + this.state = 472; + this.match(OpenSearchPPLParser.TRAINING_DATA_SIZE); + this.state = 473; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 474; + localContext._training_data_size = this.integerLiteral(); + } + } + break; + case OpenSearchPPLParser.ANOMALY_SCORE_THRESHOLD: + this.enterOuterAlt(localContext, 12); + { + { + this.state = 475; + this.match(OpenSearchPPLParser.ANOMALY_SCORE_THRESHOLD); + this.state = 476; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 477; + localContext._anomaly_score_threshold = this.decimalLiteral(); + } + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public mlCommand(): MlCommandContext { + let localContext = new MlCommandContext(this.context, this.state); + this.enterRule(localContext, 56, OpenSearchPPLParser.RULE_mlCommand); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 480; + this.match(OpenSearchPPLParser.ML); + this.state = 484; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while ((((_la) & ~0x1F) === 0 && ((1 << _la) & 3892314108) !== 0) || ((((_la - 32)) & ~0x1F) === 0 && ((1 << (_la - 32)) & 134217719) !== 0) || ((((_la - 68)) & ~0x1F) === 0 && ((1 << (_la - 68)) & 2147475455) !== 0) || ((((_la - 111)) & ~0x1F) === 0 && ((1 << (_la - 111)) & 4279238657) !== 0) || ((((_la - 143)) & ~0x1F) === 0 && ((1 << (_la - 143)) & 4294967295) !== 0) || ((((_la - 175)) & ~0x1F) === 0 && ((1 << (_la - 175)) & 4294967295) !== 0) || ((((_la - 207)) & ~0x1F) === 0 && ((1 << (_la - 207)) & 4294377471) !== 0) || ((((_la - 239)) & ~0x1F) === 0 && ((1 << (_la - 239)) & 4290772895) !== 0) || ((((_la - 271)) & ~0x1F) === 0 && ((1 << (_la - 271)) & 4294707191) !== 0) || ((((_la - 303)) & ~0x1F) === 0 && ((1 << (_la - 303)) & 67108863) !== 0) || _la === 335) { + { + { + this.state = 481; + this.mlArg(); + } + } + this.state = 486; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public mlArg(): MlArgContext { + let localContext = new MlArgContext(this.context, this.state); + this.enterRule(localContext, 58, OpenSearchPPLParser.RULE_mlArg); + try { + this.enterOuterAlt(localContext, 1); + { + { + this.state = 487; + localContext._argName = this.ident(); + this.state = 488; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 489; + localContext._argValue = this.literalValue(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public fromClause(): FromClauseContext { + let localContext = new FromClauseContext(this.context, this.state); + this.enterRule(localContext, 60, OpenSearchPPLParser.RULE_fromClause); + try { + this.state = 503; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 32, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 491; + this.match(OpenSearchPPLParser.SOURCE); + this.state = 492; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 493; + this.tableSourceClause(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 494; + this.match(OpenSearchPPLParser.INDEX); + this.state = 495; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 496; + this.tableSourceClause(); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 497; + this.match(OpenSearchPPLParser.SOURCE); + this.state = 498; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 499; + this.tableFunction(); + } + break; + case 4: + this.enterOuterAlt(localContext, 4); + { + this.state = 500; + this.match(OpenSearchPPLParser.INDEX); + this.state = 501; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 502; + this.tableFunction(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public tableSourceClause(): TableSourceClauseContext { + let localContext = new TableSourceClauseContext(this.context, this.state); + this.enterRule(localContext, 62, OpenSearchPPLParser.RULE_tableSourceClause); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 505; + this.tableSource(); + this.state = 510; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 506; + this.match(OpenSearchPPLParser.COMMA); + this.state = 507; + this.tableSource(); + } + } + this.state = 512; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public renameClasue(): RenameClasueContext { + let localContext = new RenameClasueContext(this.context, this.state); + this.enterRule(localContext, 64, OpenSearchPPLParser.RULE_renameClasue); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 513; + localContext._orignalField = this.wcFieldExpression(); + this.state = 514; + this.match(OpenSearchPPLParser.AS); + this.state = 515; + localContext._renamedField = this.wcFieldExpression(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public byClause(): ByClauseContext { + let localContext = new ByClauseContext(this.context, this.state); + this.enterRule(localContext, 66, OpenSearchPPLParser.RULE_byClause); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 517; + this.match(OpenSearchPPLParser.BY); + this.state = 518; + this.fieldList(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public statsByClause(): StatsByClauseContext { + let localContext = new StatsByClauseContext(this.context, this.state); + this.enterRule(localContext, 68, OpenSearchPPLParser.RULE_statsByClause); + try { + this.state = 529; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 34, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 520; + this.match(OpenSearchPPLParser.BY); + this.state = 521; + this.fieldList(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 522; + this.match(OpenSearchPPLParser.BY); + this.state = 523; + this.bySpanClause(); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 524; + this.match(OpenSearchPPLParser.BY); + this.state = 525; + this.bySpanClause(); + this.state = 526; + this.match(OpenSearchPPLParser.COMMA); + this.state = 527; + this.fieldList(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public bySpanClause(): BySpanClauseContext { + let localContext = new BySpanClauseContext(this.context, this.state); + this.enterRule(localContext, 70, OpenSearchPPLParser.RULE_bySpanClause); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 531; + this.spanClause(); + this.state = 534; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 27) { + { + this.state = 532; + this.match(OpenSearchPPLParser.AS); + this.state = 533; + localContext._alias = this.qualifiedName(); + } + } + + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public spanClause(): SpanClauseContext { + let localContext = new SpanClauseContext(this.context, this.state); + this.enterRule(localContext, 72, OpenSearchPPLParser.RULE_spanClause); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 536; + this.match(OpenSearchPPLParser.SPAN); + this.state = 537; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 538; + this.fieldExpression(); + this.state = 539; + this.match(OpenSearchPPLParser.COMMA); + this.state = 540; + localContext._value = this.literalValue(); + this.state = 542; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 31 || ((((_la - 70)) & ~0x1F) === 0 && ((1 << (_la - 70)) & 174612545) !== 0) || ((((_la - 321)) & ~0x1F) === 0 && ((1 << (_la - 321)) & 127) !== 0)) { + { + this.state = 541; + localContext._unit = this.timespanUnit(); + } + } + + this.state = 544; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public sortbyClause(): SortbyClauseContext { + let localContext = new SortbyClauseContext(this.context, this.state); + this.enterRule(localContext, 74, OpenSearchPPLParser.RULE_sortbyClause); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 546; + this.sortField(); + this.state = 551; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 547; + this.match(OpenSearchPPLParser.COMMA); + this.state = 548; + this.sortField(); + } + } + this.state = 553; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public evalClause(): EvalClauseContext { + let localContext = new EvalClauseContext(this.context, this.state); + this.enterRule(localContext, 76, OpenSearchPPLParser.RULE_evalClause); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 554; + this.fieldExpression(); + this.state = 555; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 556; + this.expression(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public statsAggTerm(): StatsAggTermContext { + let localContext = new StatsAggTermContext(this.context, this.state); + this.enterRule(localContext, 78, OpenSearchPPLParser.RULE_statsAggTerm); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 558; + this.statsFunction(); + this.state = 561; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 27) { + { + this.state = 559; + this.match(OpenSearchPPLParser.AS); + this.state = 560; + localContext._alias = this.wcFieldExpression(); + } + } + + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public statsFunction(): StatsFunctionContext { + let localContext = new StatsFunctionContext(this.context, this.state); + this.enterRule(localContext, 80, OpenSearchPPLParser.RULE_statsFunction); + let _la: number; + try { + this.state = 578; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 39, this.context) ) { + case 1: + localContext = new StatsFunctionCallContext(localContext); + this.enterOuterAlt(localContext, 1); + { + this.state = 563; + this.statsFunctionName(); + this.state = 564; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 565; + this.valueExpression(0); + this.state = 566; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + break; + case 2: + localContext = new CountAllFunctionCallContext(localContext); + this.enterOuterAlt(localContext, 2); + { + this.state = 568; + this.match(OpenSearchPPLParser.COUNT); + this.state = 569; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 570; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + break; + case 3: + localContext = new DistinctCountFunctionCallContext(localContext); + this.enterOuterAlt(localContext, 3); + { + this.state = 571; + _la = this.tokenStream.LA(1); + if(!(_la === 137 || _la === 171)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + this.state = 572; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 573; + this.valueExpression(0); + this.state = 574; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + break; + case 4: + localContext = new PercentileAggFunctionCallContext(localContext); + this.enterOuterAlt(localContext, 4); + { + this.state = 576; + this.percentileAggFunction(); + } + break; + case 5: + localContext = new TakeAggFunctionCallContext(localContext); + this.enterOuterAlt(localContext, 5); + { + this.state = 577; + this.takeAggFunction(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public statsFunctionName(): StatsFunctionNameContext { + let localContext = new StatsFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 82, OpenSearchPPLParser.RULE_statsFunctionName); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 580; + _la = this.tokenStream.LA(1); + if(!(((((_la - 135)) & ~0x1F) === 0 && ((1 << (_la - 135)) & 500003) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public takeAggFunction(): TakeAggFunctionContext { + let localContext = new TakeAggFunctionContext(this.context, this.state); + this.enterRule(localContext, 84, OpenSearchPPLParser.RULE_takeAggFunction); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 582; + this.match(OpenSearchPPLParser.TAKE); + this.state = 583; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 584; + this.fieldExpression(); + this.state = 587; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 110) { + { + this.state = 585; + this.match(OpenSearchPPLParser.COMMA); + this.state = 586; + localContext._size = this.integerLiteral(); + } + } + + this.state = 589; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public percentileAggFunction(): PercentileAggFunctionContext { + let localContext = new PercentileAggFunctionContext(this.context, this.state); + this.enterRule(localContext, 86, OpenSearchPPLParser.RULE_percentileAggFunction); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 591; + this.match(OpenSearchPPLParser.PERCENTILE); + this.state = 592; + this.match(OpenSearchPPLParser.LESS); + this.state = 593; + localContext._value = this.integerLiteral(); + this.state = 594; + this.match(OpenSearchPPLParser.GREATER); + this.state = 595; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 596; + localContext._aggField = this.fieldExpression(); + this.state = 597; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public expression(): ExpressionContext { + let localContext = new ExpressionContext(this.context, this.state); + this.enterRule(localContext, 88, OpenSearchPPLParser.RULE_expression); + try { + this.state = 602; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 41, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 599; + this.logicalExpression(0); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 600; + this.comparisonExpression(); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 601; + this.valueExpression(0); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + + public logicalExpression(): LogicalExpressionContext; + public logicalExpression(_p: number): LogicalExpressionContext; + public logicalExpression(_p?: number): LogicalExpressionContext { + if (_p === undefined) { + _p = 0; + } + + let parentContext = this.context; + let parentState = this.state; + let localContext = new LogicalExpressionContext(this.context, parentState); + let previousContext = localContext; + let _startState = 90; + this.enterRecursionRule(localContext, 90, OpenSearchPPLParser.RULE_logicalExpression, _p); + let _la: number; + try { + let alternative: number; + this.enterOuterAlt(localContext, 1); + { + this.state = 610; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 42, this.context) ) { + case 1: + { + localContext = new ComparsionContext(localContext); + this.context = localContext; + previousContext = localContext; + + this.state = 605; + this.comparisonExpression(); + } + break; + case 2: + { + localContext = new LogicalNotContext(localContext); + this.context = localContext; + previousContext = localContext; + this.state = 606; + this.match(OpenSearchPPLParser.NOT); + this.state = 607; + this.logicalExpression(6); + } + break; + case 3: + { + localContext = new BooleanExprContext(localContext); + this.context = localContext; + previousContext = localContext; + this.state = 608; + this.booleanExpression(); + } + break; + case 4: + { + localContext = new RelevanceExprContext(localContext); + this.context = localContext; + previousContext = localContext; + this.state = 609; + this.relevanceExpression(); + } + break; + } + this.context!.stop = this.tokenStream.LT(-1); + this.state = 625; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 45, this.context); + while (alternative !== 2 && alternative !== antlr.ATN.INVALID_ALT_NUMBER) { + if (alternative === 1) { + if (this.parseListeners != null) { + this.triggerExitRuleEvent(); + } + previousContext = localContext; + { + this.state = 623; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 44, this.context) ) { + case 1: + { + localContext = new LogicalOrContext(new LogicalExpressionContext(parentContext, parentState)); + (localContext as LogicalOrContext)._left = previousContext; + this.pushNewRecursionContext(localContext, _startState, OpenSearchPPLParser.RULE_logicalExpression); + this.state = 612; + if (!(this.precpred(this.context, 5))) { + throw this.createFailedPredicateException("this.precpred(this.context, 5)"); + } + this.state = 613; + this.match(OpenSearchPPLParser.OR); + this.state = 614; + (localContext as LogicalOrContext)._right = this.logicalExpression(6); + } + break; + case 2: + { + localContext = new LogicalAndContext(new LogicalExpressionContext(parentContext, parentState)); + (localContext as LogicalAndContext)._left = previousContext; + this.pushNewRecursionContext(localContext, _startState, OpenSearchPPLParser.RULE_logicalExpression); + this.state = 615; + if (!(this.precpred(this.context, 4))) { + throw this.createFailedPredicateException("this.precpred(this.context, 4)"); + } + this.state = 617; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 63) { + { + this.state = 616; + this.match(OpenSearchPPLParser.AND); + } + } + + this.state = 619; + (localContext as LogicalAndContext)._right = this.logicalExpression(5); + } + break; + case 3: + { + localContext = new LogicalXorContext(new LogicalExpressionContext(parentContext, parentState)); + (localContext as LogicalXorContext)._left = previousContext; + this.pushNewRecursionContext(localContext, _startState, OpenSearchPPLParser.RULE_logicalExpression); + this.state = 620; + if (!(this.precpred(this.context, 3))) { + throw this.createFailedPredicateException("this.precpred(this.context, 3)"); + } + this.state = 621; + this.match(OpenSearchPPLParser.XOR); + this.state = 622; + (localContext as LogicalXorContext)._right = this.logicalExpression(4); + } + break; + } + } + } + this.state = 627; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 45, this.context); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.unrollRecursionContexts(parentContext); + } + return localContext; + } + public comparisonExpression(): ComparisonExpressionContext { + let localContext = new ComparisonExpressionContext(this.context, this.state); + this.enterRule(localContext, 92, OpenSearchPPLParser.RULE_comparisonExpression); + try { + this.state = 636; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 46, this.context) ) { + case 1: + localContext = new CompareExprContext(localContext); + this.enterOuterAlt(localContext, 1); + { + this.state = 628; + (localContext as CompareExprContext)._left = this.valueExpression(0); + this.state = 629; + this.comparisonOperator(); + this.state = 630; + (localContext as CompareExprContext)._right = this.valueExpression(0); + } + break; + case 2: + localContext = new InExprContext(localContext); + this.enterOuterAlt(localContext, 2); + { + this.state = 632; + this.valueExpression(0); + this.state = 633; + this.match(OpenSearchPPLParser.IN); + this.state = 634; + this.valueList(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + + public valueExpression(): ValueExpressionContext; + public valueExpression(_p: number): ValueExpressionContext; + public valueExpression(_p?: number): ValueExpressionContext { + if (_p === undefined) { + _p = 0; + } + + let parentContext = this.context; + let parentState = this.state; + let localContext = new ValueExpressionContext(this.context, parentState); + let previousContext = localContext; + let _startState = 94; + this.enterRecursionRule(localContext, 94, OpenSearchPPLParser.RULE_valueExpression, _p); + let _la: number; + try { + let alternative: number; + this.enterOuterAlt(localContext, 1); + { + this.state = 648; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 47, this.context) ) { + case 1: + { + localContext = new ValueExpressionDefaultContext(localContext); + this.context = localContext; + previousContext = localContext; + + this.state = 639; + this.primaryExpression(); + } + break; + case 2: + { + localContext = new PositionFunctionCallContext(localContext); + this.context = localContext; + previousContext = localContext; + this.state = 640; + this.positionFunction(); + } + break; + case 3: + { + localContext = new ExtractFunctionCallContext(localContext); + this.context = localContext; + previousContext = localContext; + this.state = 641; + this.extractFunction(); + } + break; + case 4: + { + localContext = new GetFormatFunctionCallContext(localContext); + this.context = localContext; + previousContext = localContext; + this.state = 642; + this.getFormatFunction(); + } + break; + case 5: + { + localContext = new TimestampFunctionCallContext(localContext); + this.context = localContext; + previousContext = localContext; + this.state = 643; + this.timestampFunction(); + } + break; + case 6: + { + localContext = new ParentheticValueExprContext(localContext); + this.context = localContext; + previousContext = localContext; + this.state = 644; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 645; + this.valueExpression(0); + this.state = 646; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + break; + } + this.context!.stop = this.tokenStream.LT(-1); + this.state = 658; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 49, this.context); + while (alternative !== 2 && alternative !== antlr.ATN.INVALID_ALT_NUMBER) { + if (alternative === 1) { + if (this.parseListeners != null) { + this.triggerExitRuleEvent(); + } + previousContext = localContext; + { + this.state = 656; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 48, this.context) ) { + case 1: + { + localContext = new BinaryArithmeticContext(new ValueExpressionContext(parentContext, parentState)); + (localContext as BinaryArithmeticContext)._left = previousContext; + this.pushNewRecursionContext(localContext, _startState, OpenSearchPPLParser.RULE_valueExpression); + this.state = 650; + if (!(this.precpred(this.context, 8))) { + throw this.createFailedPredicateException("this.precpred(this.context, 8)"); + } + this.state = 651; + (localContext as BinaryArithmeticContext)._binaryOperator = this.tokenStream.LT(1); + _la = this.tokenStream.LA(1); + if(!(((((_la - 120)) & ~0x1F) === 0 && ((1 << (_la - 120)) & 7) !== 0))) { + (localContext as BinaryArithmeticContext)._binaryOperator = this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + this.state = 652; + (localContext as BinaryArithmeticContext)._right = this.valueExpression(9); + } + break; + case 2: + { + localContext = new BinaryArithmeticContext(new ValueExpressionContext(parentContext, parentState)); + (localContext as BinaryArithmeticContext)._left = previousContext; + this.pushNewRecursionContext(localContext, _startState, OpenSearchPPLParser.RULE_valueExpression); + this.state = 653; + if (!(this.precpred(this.context, 7))) { + throw this.createFailedPredicateException("this.precpred(this.context, 7)"); + } + this.state = 654; + (localContext as BinaryArithmeticContext)._binaryOperator = this.tokenStream.LT(1); + _la = this.tokenStream.LA(1); + if(!(_la === 118 || _la === 119)) { + (localContext as BinaryArithmeticContext)._binaryOperator = this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + this.state = 655; + (localContext as BinaryArithmeticContext)._right = this.valueExpression(8); + } + break; + } + } + } + this.state = 660; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 49, this.context); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.unrollRecursionContexts(parentContext); + } + return localContext; + } + public primaryExpression(): PrimaryExpressionContext { + let localContext = new PrimaryExpressionContext(this.context, this.state); + this.enterRule(localContext, 96, OpenSearchPPLParser.RULE_primaryExpression); + try { + this.state = 665; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 50, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 661; + this.evalFunctionCall(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 662; + this.dataTypeFunctionCall(); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 663; + this.fieldExpression(); + } + break; + case 4: + this.enterOuterAlt(localContext, 4); + { + this.state = 664; + this.literalValue(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public positionFunction(): PositionFunctionContext { + let localContext = new PositionFunctionContext(this.context, this.state); + this.enterRule(localContext, 98, OpenSearchPPLParser.RULE_positionFunction); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 667; + this.positionFunctionName(); + this.state = 668; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 669; + this.functionArg(); + this.state = 670; + this.match(OpenSearchPPLParser.IN); + this.state = 671; + this.functionArg(); + this.state = 672; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public booleanExpression(): BooleanExpressionContext { + let localContext = new BooleanExpressionContext(this.context, this.state); + this.enterRule(localContext, 100, OpenSearchPPLParser.RULE_booleanExpression); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 674; + this.booleanFunctionCall(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public relevanceExpression(): RelevanceExpressionContext { + let localContext = new RelevanceExpressionContext(this.context, this.state); + this.enterRule(localContext, 102, OpenSearchPPLParser.RULE_relevanceExpression); + try { + this.state = 678; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.MATCH: + case OpenSearchPPLParser.MATCH_PHRASE: + case OpenSearchPPLParser.MATCH_PHRASE_PREFIX: + case OpenSearchPPLParser.MATCH_BOOL_PREFIX: + this.enterOuterAlt(localContext, 1); + { + this.state = 676; + this.singleFieldRelevanceFunction(); + } + break; + case OpenSearchPPLParser.SIMPLE_QUERY_STRING: + case OpenSearchPPLParser.MULTI_MATCH: + case OpenSearchPPLParser.QUERY_STRING: + this.enterOuterAlt(localContext, 2); + { + this.state = 677; + this.multiFieldRelevanceFunction(); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public singleFieldRelevanceFunction(): SingleFieldRelevanceFunctionContext { + let localContext = new SingleFieldRelevanceFunctionContext(this.context, this.state); + this.enterRule(localContext, 104, OpenSearchPPLParser.RULE_singleFieldRelevanceFunction); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 680; + this.singleFieldRelevanceFunctionName(); + this.state = 681; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 682; + localContext._field = this.relevanceField(); + this.state = 683; + this.match(OpenSearchPPLParser.COMMA); + this.state = 684; + localContext._query = this.relevanceQuery(); + this.state = 689; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 685; + this.match(OpenSearchPPLParser.COMMA); + this.state = 686; + this.relevanceArg(); + } + } + this.state = 691; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + this.state = 692; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public multiFieldRelevanceFunction(): MultiFieldRelevanceFunctionContext { + let localContext = new MultiFieldRelevanceFunctionContext(this.context, this.state); + this.enterRule(localContext, 106, OpenSearchPPLParser.RULE_multiFieldRelevanceFunction); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 694; + this.multiFieldRelevanceFunctionName(); + this.state = 695; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 696; + this.match(OpenSearchPPLParser.LT_SQR_PRTHS); + this.state = 697; + localContext._field = this.relevanceFieldAndWeight(); + this.state = 702; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 698; + this.match(OpenSearchPPLParser.COMMA); + this.state = 699; + localContext._field = this.relevanceFieldAndWeight(); + } + } + this.state = 704; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + this.state = 705; + this.match(OpenSearchPPLParser.RT_SQR_PRTHS); + this.state = 706; + this.match(OpenSearchPPLParser.COMMA); + this.state = 707; + localContext._query = this.relevanceQuery(); + this.state = 712; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 708; + this.match(OpenSearchPPLParser.COMMA); + this.state = 709; + this.relevanceArg(); + } + } + this.state = 714; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + this.state = 715; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public tableSource(): TableSourceContext { + let localContext = new TableSourceContext(this.context, this.state); + this.enterRule(localContext, 108, OpenSearchPPLParser.RULE_tableSource); + try { + this.state = 719; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.SEARCH: + case OpenSearchPPLParser.DESCRIBE: + case OpenSearchPPLParser.SHOW: + case OpenSearchPPLParser.FROM: + case OpenSearchPPLParser.WHERE: + case OpenSearchPPLParser.FIELDS: + case OpenSearchPPLParser.RENAME: + case OpenSearchPPLParser.STATS: + case OpenSearchPPLParser.DEDUP: + case OpenSearchPPLParser.SORT: + case OpenSearchPPLParser.EVAL: + case OpenSearchPPLParser.HEAD: + case OpenSearchPPLParser.TOP: + case OpenSearchPPLParser.RARE: + case OpenSearchPPLParser.PARSE: + case OpenSearchPPLParser.METHOD: + case OpenSearchPPLParser.REGEX: + case OpenSearchPPLParser.PUNCT: + case OpenSearchPPLParser.GROK: + case OpenSearchPPLParser.PATTERN: + case OpenSearchPPLParser.PATTERNS: + case OpenSearchPPLParser.NEW_FIELD: + case OpenSearchPPLParser.KMEANS: + case OpenSearchPPLParser.AD: + case OpenSearchPPLParser.ML: + case OpenSearchPPLParser.SOURCE: + case OpenSearchPPLParser.INDEX: + case OpenSearchPPLParser.D: + case OpenSearchPPLParser.DESC: + case OpenSearchPPLParser.DATASOURCES: + case OpenSearchPPLParser.SORTBY: + case OpenSearchPPLParser.STR: + case OpenSearchPPLParser.IP: + case OpenSearchPPLParser.NUM: + case OpenSearchPPLParser.KEEPEMPTY: + case OpenSearchPPLParser.CONSECUTIVE: + case OpenSearchPPLParser.DEDUP_SPLITVALUES: + case OpenSearchPPLParser.PARTITIONS: + case OpenSearchPPLParser.ALLNUM: + case OpenSearchPPLParser.DELIM: + case OpenSearchPPLParser.CENTROIDS: + case OpenSearchPPLParser.ITERATIONS: + case OpenSearchPPLParser.DISTANCE_TYPE: + case OpenSearchPPLParser.NUMBER_OF_TREES: + case OpenSearchPPLParser.SHINGLE_SIZE: + case OpenSearchPPLParser.SAMPLE_SIZE: + case OpenSearchPPLParser.OUTPUT_AFTER: + case OpenSearchPPLParser.TIME_DECAY: + case OpenSearchPPLParser.ANOMALY_RATE: + case OpenSearchPPLParser.CATEGORY_FIELD: + case OpenSearchPPLParser.TIME_FIELD: + case OpenSearchPPLParser.TIME_ZONE: + case OpenSearchPPLParser.TRAINING_DATA_SIZE: + case OpenSearchPPLParser.ANOMALY_SCORE_THRESHOLD: + case OpenSearchPPLParser.CONVERT_TZ: + case OpenSearchPPLParser.DATETIME: + case OpenSearchPPLParser.DAY: + case OpenSearchPPLParser.DAY_HOUR: + case OpenSearchPPLParser.DAY_MICROSECOND: + case OpenSearchPPLParser.DAY_MINUTE: + case OpenSearchPPLParser.DAY_OF_YEAR: + case OpenSearchPPLParser.DAY_SECOND: + case OpenSearchPPLParser.HOUR: + case OpenSearchPPLParser.HOUR_MICROSECOND: + case OpenSearchPPLParser.HOUR_MINUTE: + case OpenSearchPPLParser.HOUR_OF_DAY: + case OpenSearchPPLParser.HOUR_SECOND: + case OpenSearchPPLParser.MICROSECOND: + case OpenSearchPPLParser.MILLISECOND: + case OpenSearchPPLParser.MINUTE: + case OpenSearchPPLParser.MINUTE_MICROSECOND: + case OpenSearchPPLParser.MINUTE_OF_DAY: + case OpenSearchPPLParser.MINUTE_OF_HOUR: + case OpenSearchPPLParser.MINUTE_SECOND: + case OpenSearchPPLParser.MONTH: + case OpenSearchPPLParser.MONTH_OF_YEAR: + case OpenSearchPPLParser.QUARTER: + case OpenSearchPPLParser.SECOND: + case OpenSearchPPLParser.SECOND_MICROSECOND: + case OpenSearchPPLParser.SECOND_OF_MINUTE: + case OpenSearchPPLParser.WEEK: + case OpenSearchPPLParser.WEEK_OF_YEAR: + case OpenSearchPPLParser.YEAR: + case OpenSearchPPLParser.YEAR_MONTH: + case OpenSearchPPLParser.DOT: + case OpenSearchPPLParser.BACKTICK: + case OpenSearchPPLParser.AVG: + case OpenSearchPPLParser.COUNT: + case OpenSearchPPLParser.DISTINCT_COUNT: + case OpenSearchPPLParser.ESTDC: + case OpenSearchPPLParser.ESTDC_ERROR: + case OpenSearchPPLParser.MAX: + case OpenSearchPPLParser.MEAN: + case OpenSearchPPLParser.MEDIAN: + case OpenSearchPPLParser.MIN: + case OpenSearchPPLParser.MODE: + case OpenSearchPPLParser.RANGE: + case OpenSearchPPLParser.STDEV: + case OpenSearchPPLParser.STDEVP: + case OpenSearchPPLParser.SUM: + case OpenSearchPPLParser.SUMSQ: + case OpenSearchPPLParser.VAR_SAMP: + case OpenSearchPPLParser.VAR_POP: + case OpenSearchPPLParser.STDDEV_SAMP: + case OpenSearchPPLParser.STDDEV_POP: + case OpenSearchPPLParser.PERCENTILE: + case OpenSearchPPLParser.TAKE: + case OpenSearchPPLParser.FIRST: + case OpenSearchPPLParser.LAST: + case OpenSearchPPLParser.LIST: + case OpenSearchPPLParser.VALUES: + case OpenSearchPPLParser.EARLIEST: + case OpenSearchPPLParser.EARLIEST_TIME: + case OpenSearchPPLParser.LATEST: + case OpenSearchPPLParser.LATEST_TIME: + case OpenSearchPPLParser.PER_DAY: + case OpenSearchPPLParser.PER_HOUR: + case OpenSearchPPLParser.PER_MINUTE: + case OpenSearchPPLParser.PER_SECOND: + case OpenSearchPPLParser.RATE: + case OpenSearchPPLParser.SPARKLINE: + case OpenSearchPPLParser.C: + case OpenSearchPPLParser.DC: + case OpenSearchPPLParser.ABS: + case OpenSearchPPLParser.CBRT: + case OpenSearchPPLParser.CEIL: + case OpenSearchPPLParser.CEILING: + case OpenSearchPPLParser.CONV: + case OpenSearchPPLParser.CRC32: + case OpenSearchPPLParser.E: + case OpenSearchPPLParser.EXP: + case OpenSearchPPLParser.FLOOR: + case OpenSearchPPLParser.LN: + case OpenSearchPPLParser.LOG: + case OpenSearchPPLParser.LOG10: + case OpenSearchPPLParser.LOG2: + case OpenSearchPPLParser.MOD: + case OpenSearchPPLParser.PI: + case OpenSearchPPLParser.POSITION: + case OpenSearchPPLParser.POW: + case OpenSearchPPLParser.POWER: + case OpenSearchPPLParser.RAND: + case OpenSearchPPLParser.ROUND: + case OpenSearchPPLParser.SIGN: + case OpenSearchPPLParser.SQRT: + case OpenSearchPPLParser.TRUNCATE: + case OpenSearchPPLParser.ACOS: + case OpenSearchPPLParser.ASIN: + case OpenSearchPPLParser.ATAN: + case OpenSearchPPLParser.ATAN2: + case OpenSearchPPLParser.COS: + case OpenSearchPPLParser.COT: + case OpenSearchPPLParser.DEGREES: + case OpenSearchPPLParser.RADIANS: + case OpenSearchPPLParser.SIN: + case OpenSearchPPLParser.TAN: + case OpenSearchPPLParser.ADDDATE: + case OpenSearchPPLParser.ADDTIME: + case OpenSearchPPLParser.CURDATE: + case OpenSearchPPLParser.CURRENT_DATE: + case OpenSearchPPLParser.CURRENT_TIME: + case OpenSearchPPLParser.CURRENT_TIMESTAMP: + case OpenSearchPPLParser.CURTIME: + case OpenSearchPPLParser.DATE: + case OpenSearchPPLParser.DATEDIFF: + case OpenSearchPPLParser.DATE_ADD: + case OpenSearchPPLParser.DATE_FORMAT: + case OpenSearchPPLParser.DATE_SUB: + case OpenSearchPPLParser.DAYNAME: + case OpenSearchPPLParser.DAYOFMONTH: + case OpenSearchPPLParser.DAYOFWEEK: + case OpenSearchPPLParser.DAYOFYEAR: + case OpenSearchPPLParser.DAY_OF_MONTH: + case OpenSearchPPLParser.DAY_OF_WEEK: + case OpenSearchPPLParser.FROM_DAYS: + case OpenSearchPPLParser.FROM_UNIXTIME: + case OpenSearchPPLParser.LAST_DAY: + case OpenSearchPPLParser.LOCALTIME: + case OpenSearchPPLParser.LOCALTIMESTAMP: + case OpenSearchPPLParser.MAKEDATE: + case OpenSearchPPLParser.MAKETIME: + case OpenSearchPPLParser.MONTHNAME: + case OpenSearchPPLParser.NOW: + case OpenSearchPPLParser.PERIOD_ADD: + case OpenSearchPPLParser.PERIOD_DIFF: + case OpenSearchPPLParser.SEC_TO_TIME: + case OpenSearchPPLParser.STR_TO_DATE: + case OpenSearchPPLParser.SUBDATE: + case OpenSearchPPLParser.SUBTIME: + case OpenSearchPPLParser.SYSDATE: + case OpenSearchPPLParser.TIME: + case OpenSearchPPLParser.TIMEDIFF: + case OpenSearchPPLParser.TIMESTAMP: + case OpenSearchPPLParser.TIME_FORMAT: + case OpenSearchPPLParser.TIME_TO_SEC: + case OpenSearchPPLParser.TO_DAYS: + case OpenSearchPPLParser.TO_SECONDS: + case OpenSearchPPLParser.UNIX_TIMESTAMP: + case OpenSearchPPLParser.UTC_DATE: + case OpenSearchPPLParser.UTC_TIME: + case OpenSearchPPLParser.UTC_TIMESTAMP: + case OpenSearchPPLParser.WEEKDAY: + case OpenSearchPPLParser.YEARWEEK: + case OpenSearchPPLParser.SUBSTR: + case OpenSearchPPLParser.SUBSTRING: + case OpenSearchPPLParser.LTRIM: + case OpenSearchPPLParser.RTRIM: + case OpenSearchPPLParser.TRIM: + case OpenSearchPPLParser.LOWER: + case OpenSearchPPLParser.UPPER: + case OpenSearchPPLParser.CONCAT: + case OpenSearchPPLParser.CONCAT_WS: + case OpenSearchPPLParser.LENGTH: + case OpenSearchPPLParser.STRCMP: + case OpenSearchPPLParser.RIGHT: + case OpenSearchPPLParser.LEFT: + case OpenSearchPPLParser.ASCII: + case OpenSearchPPLParser.LOCATE: + case OpenSearchPPLParser.REPLACE: + case OpenSearchPPLParser.REVERSE: + case OpenSearchPPLParser.LIKE: + case OpenSearchPPLParser.ISNULL: + case OpenSearchPPLParser.ISNOTNULL: + case OpenSearchPPLParser.IFNULL: + case OpenSearchPPLParser.NULLIF: + case OpenSearchPPLParser.IF: + case OpenSearchPPLParser.TYPEOF: + case OpenSearchPPLParser.ALLOW_LEADING_WILDCARD: + case OpenSearchPPLParser.ANALYZE_WILDCARD: + case OpenSearchPPLParser.ANALYZER: + case OpenSearchPPLParser.AUTO_GENERATE_SYNONYMS_PHRASE_QUERY: + case OpenSearchPPLParser.BOOST: + case OpenSearchPPLParser.CUTOFF_FREQUENCY: + case OpenSearchPPLParser.DEFAULT_FIELD: + case OpenSearchPPLParser.DEFAULT_OPERATOR: + case OpenSearchPPLParser.ENABLE_POSITION_INCREMENTS: + case OpenSearchPPLParser.ESCAPE: + case OpenSearchPPLParser.FLAGS: + case OpenSearchPPLParser.FUZZY_MAX_EXPANSIONS: + case OpenSearchPPLParser.FUZZY_PREFIX_LENGTH: + case OpenSearchPPLParser.FUZZY_TRANSPOSITIONS: + case OpenSearchPPLParser.FUZZY_REWRITE: + case OpenSearchPPLParser.FUZZINESS: + case OpenSearchPPLParser.LENIENT: + case OpenSearchPPLParser.LOW_FREQ_OPERATOR: + case OpenSearchPPLParser.MAX_DETERMINIZED_STATES: + case OpenSearchPPLParser.MAX_EXPANSIONS: + case OpenSearchPPLParser.MINIMUM_SHOULD_MATCH: + case OpenSearchPPLParser.OPERATOR: + case OpenSearchPPLParser.PHRASE_SLOP: + case OpenSearchPPLParser.PREFIX_LENGTH: + case OpenSearchPPLParser.QUOTE_ANALYZER: + case OpenSearchPPLParser.QUOTE_FIELD_SUFFIX: + case OpenSearchPPLParser.REWRITE: + case OpenSearchPPLParser.SLOP: + case OpenSearchPPLParser.TIE_BREAKER: + case OpenSearchPPLParser.TYPE: + case OpenSearchPPLParser.ZERO_TERMS_QUERY: + case OpenSearchPPLParser.SPAN: + case OpenSearchPPLParser.MS: + case OpenSearchPPLParser.S: + case OpenSearchPPLParser.M: + case OpenSearchPPLParser.H: + case OpenSearchPPLParser.W: + case OpenSearchPPLParser.Q: + case OpenSearchPPLParser.Y: + case OpenSearchPPLParser.ID: + case OpenSearchPPLParser.CLUSTER: + case OpenSearchPPLParser.BQUOTA_STRING: + this.enterOuterAlt(localContext, 1); + { + this.state = 717; + this.tableQualifiedName(); + } + break; + case OpenSearchPPLParser.ID_DATE_SUFFIX: + this.enterOuterAlt(localContext, 2); + { + this.state = 718; + this.match(OpenSearchPPLParser.ID_DATE_SUFFIX); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public tableFunction(): TableFunctionContext { + let localContext = new TableFunctionContext(this.context, this.state); + this.enterRule(localContext, 110, OpenSearchPPLParser.RULE_tableFunction); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 721; + this.qualifiedName(); + this.state = 722; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 723; + this.functionArgs(); + this.state = 724; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public fieldList(): FieldListContext { + let localContext = new FieldListContext(this.context, this.state); + this.enterRule(localContext, 112, OpenSearchPPLParser.RULE_fieldList); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 726; + this.fieldExpression(); + this.state = 731; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 727; + this.match(OpenSearchPPLParser.COMMA); + this.state = 728; + this.fieldExpression(); + } + } + this.state = 733; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public wcFieldList(): WcFieldListContext { + let localContext = new WcFieldListContext(this.context, this.state); + this.enterRule(localContext, 114, OpenSearchPPLParser.RULE_wcFieldList); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 734; + this.wcFieldExpression(); + this.state = 739; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 735; + this.match(OpenSearchPPLParser.COMMA); + this.state = 736; + this.wcFieldExpression(); + } + } + this.state = 741; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public sortField(): SortFieldContext { + let localContext = new SortFieldContext(this.context, this.state); + this.enterRule(localContext, 116, OpenSearchPPLParser.RULE_sortField); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 743; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 118 || _la === 119) { + { + this.state = 742; + _la = this.tokenStream.LA(1); + if(!(_la === 118 || _la === 119)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + + this.state = 745; + this.sortFieldExpression(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public sortFieldExpression(): SortFieldExpressionContext { + let localContext = new SortFieldExpressionContext(this.context, this.state); + this.enterRule(localContext, 118, OpenSearchPPLParser.RULE_sortFieldExpression); + try { + this.state = 768; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 59, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 747; + this.fieldExpression(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 748; + this.match(OpenSearchPPLParser.AUTO); + this.state = 749; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 750; + this.fieldExpression(); + this.state = 751; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 753; + this.match(OpenSearchPPLParser.STR); + this.state = 754; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 755; + this.fieldExpression(); + this.state = 756; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + break; + case 4: + this.enterOuterAlt(localContext, 4); + { + this.state = 758; + this.match(OpenSearchPPLParser.IP); + this.state = 759; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 760; + this.fieldExpression(); + this.state = 761; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + break; + case 5: + this.enterOuterAlt(localContext, 5); + { + this.state = 763; + this.match(OpenSearchPPLParser.NUM); + this.state = 764; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 765; + this.fieldExpression(); + this.state = 766; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public fieldExpression(): FieldExpressionContext { + let localContext = new FieldExpressionContext(this.context, this.state); + this.enterRule(localContext, 120, OpenSearchPPLParser.RULE_fieldExpression); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 770; + this.qualifiedName(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public wcFieldExpression(): WcFieldExpressionContext { + let localContext = new WcFieldExpressionContext(this.context, this.state); + this.enterRule(localContext, 122, OpenSearchPPLParser.RULE_wcFieldExpression); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 772; + this.wcQualifiedName(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public evalFunctionCall(): EvalFunctionCallContext { + let localContext = new EvalFunctionCallContext(this.context, this.state); + this.enterRule(localContext, 124, OpenSearchPPLParser.RULE_evalFunctionCall); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 774; + this.evalFunctionName(); + this.state = 775; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 776; + this.functionArgs(); + this.state = 777; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public dataTypeFunctionCall(): DataTypeFunctionCallContext { + let localContext = new DataTypeFunctionCallContext(this.context, this.state); + this.enterRule(localContext, 126, OpenSearchPPLParser.RULE_dataTypeFunctionCall); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 779; + this.match(OpenSearchPPLParser.CAST); + this.state = 780; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 781; + this.expression(); + this.state = 782; + this.match(OpenSearchPPLParser.AS); + this.state = 783; + this.convertedDataType(); + this.state = 784; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public booleanFunctionCall(): BooleanFunctionCallContext { + let localContext = new BooleanFunctionCallContext(this.context, this.state); + this.enterRule(localContext, 128, OpenSearchPPLParser.RULE_booleanFunctionCall); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 786; + this.conditionFunctionBase(); + this.state = 787; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 788; + this.functionArgs(); + this.state = 789; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public convertedDataType(): ConvertedDataTypeContext { + let localContext = new ConvertedDataTypeContext(this.context, this.state); + this.enterRule(localContext, 130, OpenSearchPPLParser.RULE_convertedDataType); + try { + this.state = 801; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.DATE: + this.enterOuterAlt(localContext, 1); + { + this.state = 791; + localContext._typeName = this.match(OpenSearchPPLParser.DATE); + } + break; + case OpenSearchPPLParser.TIME: + this.enterOuterAlt(localContext, 2); + { + this.state = 792; + localContext._typeName = this.match(OpenSearchPPLParser.TIME); + } + break; + case OpenSearchPPLParser.TIMESTAMP: + this.enterOuterAlt(localContext, 3); + { + this.state = 793; + localContext._typeName = this.match(OpenSearchPPLParser.TIMESTAMP); + } + break; + case OpenSearchPPLParser.INT: + this.enterOuterAlt(localContext, 4); + { + this.state = 794; + localContext._typeName = this.match(OpenSearchPPLParser.INT); + } + break; + case OpenSearchPPLParser.INTEGER: + this.enterOuterAlt(localContext, 5); + { + this.state = 795; + localContext._typeName = this.match(OpenSearchPPLParser.INTEGER); + } + break; + case OpenSearchPPLParser.DOUBLE: + this.enterOuterAlt(localContext, 6); + { + this.state = 796; + localContext._typeName = this.match(OpenSearchPPLParser.DOUBLE); + } + break; + case OpenSearchPPLParser.LONG: + this.enterOuterAlt(localContext, 7); + { + this.state = 797; + localContext._typeName = this.match(OpenSearchPPLParser.LONG); + } + break; + case OpenSearchPPLParser.FLOAT: + this.enterOuterAlt(localContext, 8); + { + this.state = 798; + localContext._typeName = this.match(OpenSearchPPLParser.FLOAT); + } + break; + case OpenSearchPPLParser.STRING: + this.enterOuterAlt(localContext, 9); + { + this.state = 799; + localContext._typeName = this.match(OpenSearchPPLParser.STRING); + } + break; + case OpenSearchPPLParser.BOOLEAN: + this.enterOuterAlt(localContext, 10); + { + this.state = 800; + localContext._typeName = this.match(OpenSearchPPLParser.BOOLEAN); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public evalFunctionName(): EvalFunctionNameContext { + let localContext = new EvalFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 132, OpenSearchPPLParser.RULE_evalFunctionName); + try { + this.state = 809; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.ABS: + case OpenSearchPPLParser.CBRT: + case OpenSearchPPLParser.CEIL: + case OpenSearchPPLParser.CEILING: + case OpenSearchPPLParser.CONV: + case OpenSearchPPLParser.CRC32: + case OpenSearchPPLParser.E: + case OpenSearchPPLParser.EXP: + case OpenSearchPPLParser.FLOOR: + case OpenSearchPPLParser.LN: + case OpenSearchPPLParser.LOG: + case OpenSearchPPLParser.LOG10: + case OpenSearchPPLParser.LOG2: + case OpenSearchPPLParser.MOD: + case OpenSearchPPLParser.PI: + case OpenSearchPPLParser.POW: + case OpenSearchPPLParser.POWER: + case OpenSearchPPLParser.RAND: + case OpenSearchPPLParser.ROUND: + case OpenSearchPPLParser.SIGN: + case OpenSearchPPLParser.SQRT: + case OpenSearchPPLParser.TRUNCATE: + case OpenSearchPPLParser.ACOS: + case OpenSearchPPLParser.ASIN: + case OpenSearchPPLParser.ATAN: + case OpenSearchPPLParser.ATAN2: + case OpenSearchPPLParser.COS: + case OpenSearchPPLParser.COT: + case OpenSearchPPLParser.DEGREES: + case OpenSearchPPLParser.RADIANS: + case OpenSearchPPLParser.SIN: + case OpenSearchPPLParser.TAN: + this.enterOuterAlt(localContext, 1); + { + this.state = 803; + this.mathematicalFunctionName(); + } + break; + case OpenSearchPPLParser.CONVERT_TZ: + case OpenSearchPPLParser.DATETIME: + case OpenSearchPPLParser.DAY: + case OpenSearchPPLParser.DAY_OF_YEAR: + case OpenSearchPPLParser.HOUR: + case OpenSearchPPLParser.HOUR_OF_DAY: + case OpenSearchPPLParser.MICROSECOND: + case OpenSearchPPLParser.MINUTE: + case OpenSearchPPLParser.MINUTE_OF_DAY: + case OpenSearchPPLParser.MINUTE_OF_HOUR: + case OpenSearchPPLParser.MONTH: + case OpenSearchPPLParser.MONTH_OF_YEAR: + case OpenSearchPPLParser.QUARTER: + case OpenSearchPPLParser.SECOND: + case OpenSearchPPLParser.SECOND_OF_MINUTE: + case OpenSearchPPLParser.WEEK: + case OpenSearchPPLParser.WEEK_OF_YEAR: + case OpenSearchPPLParser.YEAR: + case OpenSearchPPLParser.ADDDATE: + case OpenSearchPPLParser.ADDTIME: + case OpenSearchPPLParser.CURDATE: + case OpenSearchPPLParser.CURRENT_DATE: + case OpenSearchPPLParser.CURRENT_TIME: + case OpenSearchPPLParser.CURRENT_TIMESTAMP: + case OpenSearchPPLParser.CURTIME: + case OpenSearchPPLParser.DATE: + case OpenSearchPPLParser.DATEDIFF: + case OpenSearchPPLParser.DATE_ADD: + case OpenSearchPPLParser.DATE_FORMAT: + case OpenSearchPPLParser.DATE_SUB: + case OpenSearchPPLParser.DAYNAME: + case OpenSearchPPLParser.DAYOFMONTH: + case OpenSearchPPLParser.DAYOFWEEK: + case OpenSearchPPLParser.DAYOFYEAR: + case OpenSearchPPLParser.DAY_OF_MONTH: + case OpenSearchPPLParser.DAY_OF_WEEK: + case OpenSearchPPLParser.FROM_DAYS: + case OpenSearchPPLParser.FROM_UNIXTIME: + case OpenSearchPPLParser.LAST_DAY: + case OpenSearchPPLParser.LOCALTIME: + case OpenSearchPPLParser.LOCALTIMESTAMP: + case OpenSearchPPLParser.MAKEDATE: + case OpenSearchPPLParser.MAKETIME: + case OpenSearchPPLParser.MONTHNAME: + case OpenSearchPPLParser.NOW: + case OpenSearchPPLParser.PERIOD_ADD: + case OpenSearchPPLParser.PERIOD_DIFF: + case OpenSearchPPLParser.SEC_TO_TIME: + case OpenSearchPPLParser.STR_TO_DATE: + case OpenSearchPPLParser.SUBDATE: + case OpenSearchPPLParser.SUBTIME: + case OpenSearchPPLParser.SYSDATE: + case OpenSearchPPLParser.TIME: + case OpenSearchPPLParser.TIMEDIFF: + case OpenSearchPPLParser.TIMESTAMP: + case OpenSearchPPLParser.TIME_FORMAT: + case OpenSearchPPLParser.TIME_TO_SEC: + case OpenSearchPPLParser.TO_DAYS: + case OpenSearchPPLParser.TO_SECONDS: + case OpenSearchPPLParser.UNIX_TIMESTAMP: + case OpenSearchPPLParser.UTC_DATE: + case OpenSearchPPLParser.UTC_TIME: + case OpenSearchPPLParser.UTC_TIMESTAMP: + case OpenSearchPPLParser.WEEKDAY: + case OpenSearchPPLParser.YEARWEEK: + this.enterOuterAlt(localContext, 2); + { + this.state = 804; + this.dateTimeFunctionName(); + } + break; + case OpenSearchPPLParser.SUBSTR: + case OpenSearchPPLParser.SUBSTRING: + case OpenSearchPPLParser.LTRIM: + case OpenSearchPPLParser.RTRIM: + case OpenSearchPPLParser.TRIM: + case OpenSearchPPLParser.LOWER: + case OpenSearchPPLParser.UPPER: + case OpenSearchPPLParser.CONCAT: + case OpenSearchPPLParser.CONCAT_WS: + case OpenSearchPPLParser.LENGTH: + case OpenSearchPPLParser.STRCMP: + case OpenSearchPPLParser.RIGHT: + case OpenSearchPPLParser.LEFT: + case OpenSearchPPLParser.ASCII: + case OpenSearchPPLParser.LOCATE: + case OpenSearchPPLParser.REPLACE: + case OpenSearchPPLParser.REVERSE: + this.enterOuterAlt(localContext, 3); + { + this.state = 805; + this.textFunctionName(); + } + break; + case OpenSearchPPLParser.LIKE: + case OpenSearchPPLParser.ISNULL: + case OpenSearchPPLParser.ISNOTNULL: + case OpenSearchPPLParser.IFNULL: + case OpenSearchPPLParser.NULLIF: + case OpenSearchPPLParser.IF: + this.enterOuterAlt(localContext, 4); + { + this.state = 806; + this.conditionFunctionBase(); + } + break; + case OpenSearchPPLParser.TYPEOF: + this.enterOuterAlt(localContext, 5); + { + this.state = 807; + this.systemFunctionName(); + } + break; + case OpenSearchPPLParser.POSITION: + this.enterOuterAlt(localContext, 6); + { + this.state = 808; + this.positionFunctionName(); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public functionArgs(): FunctionArgsContext { + let localContext = new FunctionArgsContext(this.context, this.state); + this.enterRule(localContext, 134, OpenSearchPPLParser.RULE_functionArgs); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 819; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if ((((_la) & ~0x1F) === 0 && ((1 << _la) & 3892314108) !== 0) || ((((_la - 32)) & ~0x1F) === 0 && ((1 << (_la - 32)) & 134217719) !== 0) || ((((_la - 65)) & ~0x1F) === 0 && ((1 << (_la - 65)) & 4294967291) !== 0) || ((((_la - 97)) & ~0x1F) === 0 && ((1 << (_la - 97)) & 274743299) !== 0) || ((((_la - 131)) & ~0x1F) === 0 && ((1 << (_la - 131)) & 4294967281) !== 0) || ((((_la - 163)) & ~0x1F) === 0 && ((1 << (_la - 163)) & 4294967295) !== 0) || ((((_la - 195)) & ~0x1F) === 0 && ((1 << (_la - 195)) & 4294967295) !== 0) || ((((_la - 227)) & ~0x1F) === 0 && ((1 << (_la - 227)) & 4294967295) !== 0) || ((((_la - 259)) & ~0x1F) === 0 && ((1 << (_la - 259)) & 3229614075) !== 0) || ((((_la - 291)) & ~0x1F) === 0 && ((1 << (_la - 291)) & 4294967295) !== 0) || ((((_la - 323)) & ~0x1F) === 0 && ((1 << (_la - 323)) & 7615) !== 0)) { + { + this.state = 811; + this.functionArg(); + this.state = 816; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 812; + this.match(OpenSearchPPLParser.COMMA); + this.state = 813; + this.functionArg(); + } + } + this.state = 818; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public functionArg(): FunctionArgContext { + let localContext = new FunctionArgContext(this.context, this.state); + this.enterRule(localContext, 136, OpenSearchPPLParser.RULE_functionArg); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 824; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 64, this.context) ) { + case 1: + { + this.state = 821; + this.ident(); + this.state = 822; + this.match(OpenSearchPPLParser.EQUAL); + } + break; + } + this.state = 826; + this.valueExpression(0); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public relevanceArg(): RelevanceArgContext { + let localContext = new RelevanceArgContext(this.context, this.state); + this.enterRule(localContext, 138, OpenSearchPPLParser.RULE_relevanceArg); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 828; + this.relevanceArgName(); + this.state = 829; + this.match(OpenSearchPPLParser.EQUAL); + this.state = 830; + this.relevanceArgValue(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public relevanceArgName(): RelevanceArgNameContext { + let localContext = new RelevanceArgNameContext(this.context, this.state); + this.enterRule(localContext, 140, OpenSearchPPLParser.RULE_relevanceArgName); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 832; + _la = this.tokenStream.LA(1); + if(!(_la === 7 || _la === 56 || ((((_la - 289)) & ~0x1F) === 0 && ((1 << (_la - 289)) & 2147483647) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public relevanceFieldAndWeight(): RelevanceFieldAndWeightContext { + let localContext = new RelevanceFieldAndWeightContext(this.context, this.state); + this.enterRule(localContext, 142, OpenSearchPPLParser.RULE_relevanceFieldAndWeight); + try { + this.state = 842; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 65, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 834; + localContext._field = this.relevanceField(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 835; + localContext._field = this.relevanceField(); + this.state = 836; + localContext._weight = this.relevanceFieldWeight(); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 838; + localContext._field = this.relevanceField(); + this.state = 839; + this.match(OpenSearchPPLParser.BIT_XOR_OP); + this.state = 840; + localContext._weight = this.relevanceFieldWeight(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public relevanceFieldWeight(): RelevanceFieldWeightContext { + let localContext = new RelevanceFieldWeightContext(this.context, this.state); + this.enterRule(localContext, 144, OpenSearchPPLParser.RULE_relevanceFieldWeight); + try { + this.state = 846; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 66, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 844; + this.integerLiteral(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 845; + this.decimalLiteral(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public relevanceField(): RelevanceFieldContext { + let localContext = new RelevanceFieldContext(this.context, this.state); + this.enterRule(localContext, 146, OpenSearchPPLParser.RULE_relevanceField); + try { + this.state = 850; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.SEARCH: + case OpenSearchPPLParser.DESCRIBE: + case OpenSearchPPLParser.SHOW: + case OpenSearchPPLParser.FROM: + case OpenSearchPPLParser.WHERE: + case OpenSearchPPLParser.FIELDS: + case OpenSearchPPLParser.RENAME: + case OpenSearchPPLParser.STATS: + case OpenSearchPPLParser.DEDUP: + case OpenSearchPPLParser.SORT: + case OpenSearchPPLParser.EVAL: + case OpenSearchPPLParser.HEAD: + case OpenSearchPPLParser.TOP: + case OpenSearchPPLParser.RARE: + case OpenSearchPPLParser.PARSE: + case OpenSearchPPLParser.METHOD: + case OpenSearchPPLParser.REGEX: + case OpenSearchPPLParser.PUNCT: + case OpenSearchPPLParser.GROK: + case OpenSearchPPLParser.PATTERN: + case OpenSearchPPLParser.PATTERNS: + case OpenSearchPPLParser.NEW_FIELD: + case OpenSearchPPLParser.KMEANS: + case OpenSearchPPLParser.AD: + case OpenSearchPPLParser.ML: + case OpenSearchPPLParser.SOURCE: + case OpenSearchPPLParser.INDEX: + case OpenSearchPPLParser.D: + case OpenSearchPPLParser.DESC: + case OpenSearchPPLParser.DATASOURCES: + case OpenSearchPPLParser.SORTBY: + case OpenSearchPPLParser.STR: + case OpenSearchPPLParser.IP: + case OpenSearchPPLParser.NUM: + case OpenSearchPPLParser.KEEPEMPTY: + case OpenSearchPPLParser.CONSECUTIVE: + case OpenSearchPPLParser.DEDUP_SPLITVALUES: + case OpenSearchPPLParser.PARTITIONS: + case OpenSearchPPLParser.ALLNUM: + case OpenSearchPPLParser.DELIM: + case OpenSearchPPLParser.CENTROIDS: + case OpenSearchPPLParser.ITERATIONS: + case OpenSearchPPLParser.DISTANCE_TYPE: + case OpenSearchPPLParser.NUMBER_OF_TREES: + case OpenSearchPPLParser.SHINGLE_SIZE: + case OpenSearchPPLParser.SAMPLE_SIZE: + case OpenSearchPPLParser.OUTPUT_AFTER: + case OpenSearchPPLParser.TIME_DECAY: + case OpenSearchPPLParser.ANOMALY_RATE: + case OpenSearchPPLParser.CATEGORY_FIELD: + case OpenSearchPPLParser.TIME_FIELD: + case OpenSearchPPLParser.TIME_ZONE: + case OpenSearchPPLParser.TRAINING_DATA_SIZE: + case OpenSearchPPLParser.ANOMALY_SCORE_THRESHOLD: + case OpenSearchPPLParser.CONVERT_TZ: + case OpenSearchPPLParser.DATETIME: + case OpenSearchPPLParser.DAY: + case OpenSearchPPLParser.DAY_HOUR: + case OpenSearchPPLParser.DAY_MICROSECOND: + case OpenSearchPPLParser.DAY_MINUTE: + case OpenSearchPPLParser.DAY_OF_YEAR: + case OpenSearchPPLParser.DAY_SECOND: + case OpenSearchPPLParser.HOUR: + case OpenSearchPPLParser.HOUR_MICROSECOND: + case OpenSearchPPLParser.HOUR_MINUTE: + case OpenSearchPPLParser.HOUR_OF_DAY: + case OpenSearchPPLParser.HOUR_SECOND: + case OpenSearchPPLParser.MICROSECOND: + case OpenSearchPPLParser.MILLISECOND: + case OpenSearchPPLParser.MINUTE: + case OpenSearchPPLParser.MINUTE_MICROSECOND: + case OpenSearchPPLParser.MINUTE_OF_DAY: + case OpenSearchPPLParser.MINUTE_OF_HOUR: + case OpenSearchPPLParser.MINUTE_SECOND: + case OpenSearchPPLParser.MONTH: + case OpenSearchPPLParser.MONTH_OF_YEAR: + case OpenSearchPPLParser.QUARTER: + case OpenSearchPPLParser.SECOND: + case OpenSearchPPLParser.SECOND_MICROSECOND: + case OpenSearchPPLParser.SECOND_OF_MINUTE: + case OpenSearchPPLParser.WEEK: + case OpenSearchPPLParser.WEEK_OF_YEAR: + case OpenSearchPPLParser.YEAR: + case OpenSearchPPLParser.YEAR_MONTH: + case OpenSearchPPLParser.DOT: + case OpenSearchPPLParser.BACKTICK: + case OpenSearchPPLParser.AVG: + case OpenSearchPPLParser.COUNT: + case OpenSearchPPLParser.DISTINCT_COUNT: + case OpenSearchPPLParser.ESTDC: + case OpenSearchPPLParser.ESTDC_ERROR: + case OpenSearchPPLParser.MAX: + case OpenSearchPPLParser.MEAN: + case OpenSearchPPLParser.MEDIAN: + case OpenSearchPPLParser.MIN: + case OpenSearchPPLParser.MODE: + case OpenSearchPPLParser.RANGE: + case OpenSearchPPLParser.STDEV: + case OpenSearchPPLParser.STDEVP: + case OpenSearchPPLParser.SUM: + case OpenSearchPPLParser.SUMSQ: + case OpenSearchPPLParser.VAR_SAMP: + case OpenSearchPPLParser.VAR_POP: + case OpenSearchPPLParser.STDDEV_SAMP: + case OpenSearchPPLParser.STDDEV_POP: + case OpenSearchPPLParser.PERCENTILE: + case OpenSearchPPLParser.TAKE: + case OpenSearchPPLParser.FIRST: + case OpenSearchPPLParser.LAST: + case OpenSearchPPLParser.LIST: + case OpenSearchPPLParser.VALUES: + case OpenSearchPPLParser.EARLIEST: + case OpenSearchPPLParser.EARLIEST_TIME: + case OpenSearchPPLParser.LATEST: + case OpenSearchPPLParser.LATEST_TIME: + case OpenSearchPPLParser.PER_DAY: + case OpenSearchPPLParser.PER_HOUR: + case OpenSearchPPLParser.PER_MINUTE: + case OpenSearchPPLParser.PER_SECOND: + case OpenSearchPPLParser.RATE: + case OpenSearchPPLParser.SPARKLINE: + case OpenSearchPPLParser.C: + case OpenSearchPPLParser.DC: + case OpenSearchPPLParser.ABS: + case OpenSearchPPLParser.CBRT: + case OpenSearchPPLParser.CEIL: + case OpenSearchPPLParser.CEILING: + case OpenSearchPPLParser.CONV: + case OpenSearchPPLParser.CRC32: + case OpenSearchPPLParser.E: + case OpenSearchPPLParser.EXP: + case OpenSearchPPLParser.FLOOR: + case OpenSearchPPLParser.LN: + case OpenSearchPPLParser.LOG: + case OpenSearchPPLParser.LOG10: + case OpenSearchPPLParser.LOG2: + case OpenSearchPPLParser.MOD: + case OpenSearchPPLParser.PI: + case OpenSearchPPLParser.POSITION: + case OpenSearchPPLParser.POW: + case OpenSearchPPLParser.POWER: + case OpenSearchPPLParser.RAND: + case OpenSearchPPLParser.ROUND: + case OpenSearchPPLParser.SIGN: + case OpenSearchPPLParser.SQRT: + case OpenSearchPPLParser.TRUNCATE: + case OpenSearchPPLParser.ACOS: + case OpenSearchPPLParser.ASIN: + case OpenSearchPPLParser.ATAN: + case OpenSearchPPLParser.ATAN2: + case OpenSearchPPLParser.COS: + case OpenSearchPPLParser.COT: + case OpenSearchPPLParser.DEGREES: + case OpenSearchPPLParser.RADIANS: + case OpenSearchPPLParser.SIN: + case OpenSearchPPLParser.TAN: + case OpenSearchPPLParser.ADDDATE: + case OpenSearchPPLParser.ADDTIME: + case OpenSearchPPLParser.CURDATE: + case OpenSearchPPLParser.CURRENT_DATE: + case OpenSearchPPLParser.CURRENT_TIME: + case OpenSearchPPLParser.CURRENT_TIMESTAMP: + case OpenSearchPPLParser.CURTIME: + case OpenSearchPPLParser.DATE: + case OpenSearchPPLParser.DATEDIFF: + case OpenSearchPPLParser.DATE_ADD: + case OpenSearchPPLParser.DATE_FORMAT: + case OpenSearchPPLParser.DATE_SUB: + case OpenSearchPPLParser.DAYNAME: + case OpenSearchPPLParser.DAYOFMONTH: + case OpenSearchPPLParser.DAYOFWEEK: + case OpenSearchPPLParser.DAYOFYEAR: + case OpenSearchPPLParser.DAY_OF_MONTH: + case OpenSearchPPLParser.DAY_OF_WEEK: + case OpenSearchPPLParser.FROM_DAYS: + case OpenSearchPPLParser.FROM_UNIXTIME: + case OpenSearchPPLParser.LAST_DAY: + case OpenSearchPPLParser.LOCALTIME: + case OpenSearchPPLParser.LOCALTIMESTAMP: + case OpenSearchPPLParser.MAKEDATE: + case OpenSearchPPLParser.MAKETIME: + case OpenSearchPPLParser.MONTHNAME: + case OpenSearchPPLParser.NOW: + case OpenSearchPPLParser.PERIOD_ADD: + case OpenSearchPPLParser.PERIOD_DIFF: + case OpenSearchPPLParser.SEC_TO_TIME: + case OpenSearchPPLParser.STR_TO_DATE: + case OpenSearchPPLParser.SUBDATE: + case OpenSearchPPLParser.SUBTIME: + case OpenSearchPPLParser.SYSDATE: + case OpenSearchPPLParser.TIME: + case OpenSearchPPLParser.TIMEDIFF: + case OpenSearchPPLParser.TIMESTAMP: + case OpenSearchPPLParser.TIME_FORMAT: + case OpenSearchPPLParser.TIME_TO_SEC: + case OpenSearchPPLParser.TO_DAYS: + case OpenSearchPPLParser.TO_SECONDS: + case OpenSearchPPLParser.UNIX_TIMESTAMP: + case OpenSearchPPLParser.UTC_DATE: + case OpenSearchPPLParser.UTC_TIME: + case OpenSearchPPLParser.UTC_TIMESTAMP: + case OpenSearchPPLParser.WEEKDAY: + case OpenSearchPPLParser.YEARWEEK: + case OpenSearchPPLParser.SUBSTR: + case OpenSearchPPLParser.SUBSTRING: + case OpenSearchPPLParser.LTRIM: + case OpenSearchPPLParser.RTRIM: + case OpenSearchPPLParser.TRIM: + case OpenSearchPPLParser.LOWER: + case OpenSearchPPLParser.UPPER: + case OpenSearchPPLParser.CONCAT: + case OpenSearchPPLParser.CONCAT_WS: + case OpenSearchPPLParser.LENGTH: + case OpenSearchPPLParser.STRCMP: + case OpenSearchPPLParser.RIGHT: + case OpenSearchPPLParser.LEFT: + case OpenSearchPPLParser.ASCII: + case OpenSearchPPLParser.LOCATE: + case OpenSearchPPLParser.REPLACE: + case OpenSearchPPLParser.REVERSE: + case OpenSearchPPLParser.LIKE: + case OpenSearchPPLParser.ISNULL: + case OpenSearchPPLParser.ISNOTNULL: + case OpenSearchPPLParser.IFNULL: + case OpenSearchPPLParser.NULLIF: + case OpenSearchPPLParser.IF: + case OpenSearchPPLParser.TYPEOF: + case OpenSearchPPLParser.ALLOW_LEADING_WILDCARD: + case OpenSearchPPLParser.ANALYZE_WILDCARD: + case OpenSearchPPLParser.ANALYZER: + case OpenSearchPPLParser.AUTO_GENERATE_SYNONYMS_PHRASE_QUERY: + case OpenSearchPPLParser.BOOST: + case OpenSearchPPLParser.CUTOFF_FREQUENCY: + case OpenSearchPPLParser.DEFAULT_FIELD: + case OpenSearchPPLParser.DEFAULT_OPERATOR: + case OpenSearchPPLParser.ENABLE_POSITION_INCREMENTS: + case OpenSearchPPLParser.ESCAPE: + case OpenSearchPPLParser.FLAGS: + case OpenSearchPPLParser.FUZZY_MAX_EXPANSIONS: + case OpenSearchPPLParser.FUZZY_PREFIX_LENGTH: + case OpenSearchPPLParser.FUZZY_TRANSPOSITIONS: + case OpenSearchPPLParser.FUZZY_REWRITE: + case OpenSearchPPLParser.FUZZINESS: + case OpenSearchPPLParser.LENIENT: + case OpenSearchPPLParser.LOW_FREQ_OPERATOR: + case OpenSearchPPLParser.MAX_DETERMINIZED_STATES: + case OpenSearchPPLParser.MAX_EXPANSIONS: + case OpenSearchPPLParser.MINIMUM_SHOULD_MATCH: + case OpenSearchPPLParser.OPERATOR: + case OpenSearchPPLParser.PHRASE_SLOP: + case OpenSearchPPLParser.PREFIX_LENGTH: + case OpenSearchPPLParser.QUOTE_ANALYZER: + case OpenSearchPPLParser.QUOTE_FIELD_SUFFIX: + case OpenSearchPPLParser.REWRITE: + case OpenSearchPPLParser.SLOP: + case OpenSearchPPLParser.TIE_BREAKER: + case OpenSearchPPLParser.TYPE: + case OpenSearchPPLParser.ZERO_TERMS_QUERY: + case OpenSearchPPLParser.SPAN: + case OpenSearchPPLParser.MS: + case OpenSearchPPLParser.S: + case OpenSearchPPLParser.M: + case OpenSearchPPLParser.H: + case OpenSearchPPLParser.W: + case OpenSearchPPLParser.Q: + case OpenSearchPPLParser.Y: + case OpenSearchPPLParser.ID: + case OpenSearchPPLParser.BQUOTA_STRING: + this.enterOuterAlt(localContext, 1); + { + this.state = 848; + this.qualifiedName(); + } + break; + case OpenSearchPPLParser.DQUOTA_STRING: + case OpenSearchPPLParser.SQUOTA_STRING: + this.enterOuterAlt(localContext, 2); + { + this.state = 849; + this.stringLiteral(); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public relevanceQuery(): RelevanceQueryContext { + let localContext = new RelevanceQueryContext(this.context, this.state); + this.enterRule(localContext, 148, OpenSearchPPLParser.RULE_relevanceQuery); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 852; + this.relevanceArgValue(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public relevanceArgValue(): RelevanceArgValueContext { + let localContext = new RelevanceArgValueContext(this.context, this.state); + this.enterRule(localContext, 150, OpenSearchPPLParser.RULE_relevanceArgValue); + try { + this.state = 856; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 68, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 854; + this.qualifiedName(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 855; + this.literalValue(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public mathematicalFunctionName(): MathematicalFunctionNameContext { + let localContext = new MathematicalFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 152, OpenSearchPPLParser.RULE_mathematicalFunctionName); + try { + this.state = 881; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.ABS: + this.enterOuterAlt(localContext, 1); + { + this.state = 858; + this.match(OpenSearchPPLParser.ABS); + } + break; + case OpenSearchPPLParser.CBRT: + this.enterOuterAlt(localContext, 2); + { + this.state = 859; + this.match(OpenSearchPPLParser.CBRT); + } + break; + case OpenSearchPPLParser.CEIL: + this.enterOuterAlt(localContext, 3); + { + this.state = 860; + this.match(OpenSearchPPLParser.CEIL); + } + break; + case OpenSearchPPLParser.CEILING: + this.enterOuterAlt(localContext, 4); + { + this.state = 861; + this.match(OpenSearchPPLParser.CEILING); + } + break; + case OpenSearchPPLParser.CONV: + this.enterOuterAlt(localContext, 5); + { + this.state = 862; + this.match(OpenSearchPPLParser.CONV); + } + break; + case OpenSearchPPLParser.CRC32: + this.enterOuterAlt(localContext, 6); + { + this.state = 863; + this.match(OpenSearchPPLParser.CRC32); + } + break; + case OpenSearchPPLParser.E: + this.enterOuterAlt(localContext, 7); + { + this.state = 864; + this.match(OpenSearchPPLParser.E); + } + break; + case OpenSearchPPLParser.EXP: + this.enterOuterAlt(localContext, 8); + { + this.state = 865; + this.match(OpenSearchPPLParser.EXP); + } + break; + case OpenSearchPPLParser.FLOOR: + this.enterOuterAlt(localContext, 9); + { + this.state = 866; + this.match(OpenSearchPPLParser.FLOOR); + } + break; + case OpenSearchPPLParser.LN: + this.enterOuterAlt(localContext, 10); + { + this.state = 867; + this.match(OpenSearchPPLParser.LN); + } + break; + case OpenSearchPPLParser.LOG: + this.enterOuterAlt(localContext, 11); + { + this.state = 868; + this.match(OpenSearchPPLParser.LOG); + } + break; + case OpenSearchPPLParser.LOG10: + this.enterOuterAlt(localContext, 12); + { + this.state = 869; + this.match(OpenSearchPPLParser.LOG10); + } + break; + case OpenSearchPPLParser.LOG2: + this.enterOuterAlt(localContext, 13); + { + this.state = 870; + this.match(OpenSearchPPLParser.LOG2); + } + break; + case OpenSearchPPLParser.MOD: + this.enterOuterAlt(localContext, 14); + { + this.state = 871; + this.match(OpenSearchPPLParser.MOD); + } + break; + case OpenSearchPPLParser.PI: + this.enterOuterAlt(localContext, 15); + { + this.state = 872; + this.match(OpenSearchPPLParser.PI); + } + break; + case OpenSearchPPLParser.POW: + this.enterOuterAlt(localContext, 16); + { + this.state = 873; + this.match(OpenSearchPPLParser.POW); + } + break; + case OpenSearchPPLParser.POWER: + this.enterOuterAlt(localContext, 17); + { + this.state = 874; + this.match(OpenSearchPPLParser.POWER); + } + break; + case OpenSearchPPLParser.RAND: + this.enterOuterAlt(localContext, 18); + { + this.state = 875; + this.match(OpenSearchPPLParser.RAND); + } + break; + case OpenSearchPPLParser.ROUND: + this.enterOuterAlt(localContext, 19); + { + this.state = 876; + this.match(OpenSearchPPLParser.ROUND); + } + break; + case OpenSearchPPLParser.SIGN: + this.enterOuterAlt(localContext, 20); + { + this.state = 877; + this.match(OpenSearchPPLParser.SIGN); + } + break; + case OpenSearchPPLParser.SQRT: + this.enterOuterAlt(localContext, 21); + { + this.state = 878; + this.match(OpenSearchPPLParser.SQRT); + } + break; + case OpenSearchPPLParser.TRUNCATE: + this.enterOuterAlt(localContext, 22); + { + this.state = 879; + this.match(OpenSearchPPLParser.TRUNCATE); + } + break; + case OpenSearchPPLParser.ACOS: + case OpenSearchPPLParser.ASIN: + case OpenSearchPPLParser.ATAN: + case OpenSearchPPLParser.ATAN2: + case OpenSearchPPLParser.COS: + case OpenSearchPPLParser.COT: + case OpenSearchPPLParser.DEGREES: + case OpenSearchPPLParser.RADIANS: + case OpenSearchPPLParser.SIN: + case OpenSearchPPLParser.TAN: + this.enterOuterAlt(localContext, 23); + { + this.state = 880; + this.trigonometricFunctionName(); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public trigonometricFunctionName(): TrigonometricFunctionNameContext { + let localContext = new TrigonometricFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 154, OpenSearchPPLParser.RULE_trigonometricFunctionName); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 883; + _la = this.tokenStream.LA(1); + if(!(((((_la - 195)) & ~0x1F) === 0 && ((1 << (_la - 195)) & 1023) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public dateTimeFunctionName(): DateTimeFunctionNameContext { + let localContext = new DateTimeFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 156, OpenSearchPPLParser.RULE_dateTimeFunctionName); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 885; + _la = this.tokenStream.LA(1); + if(!(((((_la - 68)) & ~0x1F) === 0 && ((1 << (_la - 68)) & 1038960967) !== 0) || ((((_la - 205)) & ~0x1F) === 0 && ((1 << (_la - 205)) & 4292607999) !== 0) || ((((_la - 237)) & ~0x1F) === 0 && ((1 << (_la - 237)) & 523903) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public getFormatFunction(): GetFormatFunctionContext { + let localContext = new GetFormatFunctionContext(this.context, this.state); + this.enterRule(localContext, 158, OpenSearchPPLParser.RULE_getFormatFunction); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 887; + this.match(OpenSearchPPLParser.GET_FORMAT); + this.state = 888; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 889; + this.getFormatType(); + this.state = 890; + this.match(OpenSearchPPLParser.COMMA); + this.state = 891; + this.functionArg(); + this.state = 892; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public getFormatType(): GetFormatTypeContext { + let localContext = new GetFormatTypeContext(this.context, this.state); + this.enterRule(localContext, 160, OpenSearchPPLParser.RULE_getFormatType); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 894; + _la = this.tokenStream.LA(1); + if(!(_la === 69 || ((((_la - 212)) & ~0x1F) === 0 && ((1 << (_la - 212)) & 2684354561) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public extractFunction(): ExtractFunctionContext { + let localContext = new ExtractFunctionContext(this.context, this.state); + this.enterRule(localContext, 162, OpenSearchPPLParser.RULE_extractFunction); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 896; + this.match(OpenSearchPPLParser.EXTRACT); + this.state = 897; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 898; + this.datetimePart(); + this.state = 899; + this.match(OpenSearchPPLParser.FROM); + this.state = 900; + this.functionArg(); + this.state = 901; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public simpleDateTimePart(): SimpleDateTimePartContext { + let localContext = new SimpleDateTimePartContext(this.context, this.state); + this.enterRule(localContext, 164, OpenSearchPPLParser.RULE_simpleDateTimePart); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 903; + _la = this.tokenStream.LA(1); + if(!(((((_la - 70)) & ~0x1F) === 0 && ((1 << (_la - 70)) & 174608449) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public complexDateTimePart(): ComplexDateTimePartContext { + let localContext = new ComplexDateTimePartContext(this.context, this.state); + this.enterRule(localContext, 166, OpenSearchPPLParser.RULE_complexDateTimePart); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 905; + _la = this.tokenStream.LA(1); + if(!(((((_la - 71)) & ~0x1F) === 0 && ((1 << (_la - 71)) & 138560215) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public datetimePart(): DatetimePartContext { + let localContext = new DatetimePartContext(this.context, this.state); + this.enterRule(localContext, 168, OpenSearchPPLParser.RULE_datetimePart); + try { + this.state = 909; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.DAY: + case OpenSearchPPLParser.HOUR: + case OpenSearchPPLParser.MICROSECOND: + case OpenSearchPPLParser.MINUTE: + case OpenSearchPPLParser.MONTH: + case OpenSearchPPLParser.QUARTER: + case OpenSearchPPLParser.SECOND: + case OpenSearchPPLParser.WEEK: + case OpenSearchPPLParser.YEAR: + this.enterOuterAlt(localContext, 1); + { + this.state = 907; + this.simpleDateTimePart(); + } + break; + case OpenSearchPPLParser.DAY_HOUR: + case OpenSearchPPLParser.DAY_MICROSECOND: + case OpenSearchPPLParser.DAY_MINUTE: + case OpenSearchPPLParser.DAY_SECOND: + case OpenSearchPPLParser.HOUR_MICROSECOND: + case OpenSearchPPLParser.HOUR_MINUTE: + case OpenSearchPPLParser.HOUR_SECOND: + case OpenSearchPPLParser.MINUTE_MICROSECOND: + case OpenSearchPPLParser.MINUTE_SECOND: + case OpenSearchPPLParser.SECOND_MICROSECOND: + case OpenSearchPPLParser.YEAR_MONTH: + this.enterOuterAlt(localContext, 2); + { + this.state = 908; + this.complexDateTimePart(); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public timestampFunction(): TimestampFunctionContext { + let localContext = new TimestampFunctionContext(this.context, this.state); + this.enterRule(localContext, 170, OpenSearchPPLParser.RULE_timestampFunction); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 911; + this.timestampFunctionName(); + this.state = 912; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 913; + this.simpleDateTimePart(); + this.state = 914; + this.match(OpenSearchPPLParser.COMMA); + this.state = 915; + localContext._firstArg = this.functionArg(); + this.state = 916; + this.match(OpenSearchPPLParser.COMMA); + this.state = 917; + localContext._secondArg = this.functionArg(); + this.state = 918; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public timestampFunctionName(): TimestampFunctionNameContext { + let localContext = new TimestampFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 172, OpenSearchPPLParser.RULE_timestampFunctionName); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 920; + _la = this.tokenStream.LA(1); + if(!(_la === 244 || _la === 245)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public conditionFunctionBase(): ConditionFunctionBaseContext { + let localContext = new ConditionFunctionBaseContext(this.context, this.state); + this.enterRule(localContext, 174, OpenSearchPPLParser.RULE_conditionFunctionBase); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 922; + _la = this.tokenStream.LA(1); + if(!(((((_la - 275)) & ~0x1F) === 0 && ((1 << (_la - 275)) & 63) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public systemFunctionName(): SystemFunctionNameContext { + let localContext = new SystemFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 176, OpenSearchPPLParser.RULE_systemFunctionName); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 924; + this.match(OpenSearchPPLParser.TYPEOF); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public textFunctionName(): TextFunctionNameContext { + let localContext = new TextFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 178, OpenSearchPPLParser.RULE_textFunctionName); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 926; + _la = this.tokenStream.LA(1); + if(!(((((_la - 256)) & ~0x1F) === 0 && ((1 << (_la - 256)) & 262111) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public positionFunctionName(): PositionFunctionNameContext { + let localContext = new PositionFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 180, OpenSearchPPLParser.RULE_positionFunctionName); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 928; + this.match(OpenSearchPPLParser.POSITION); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public comparisonOperator(): ComparisonOperatorContext { + let localContext = new ComparisonOperatorContext(this.context, this.state); + this.enterRule(localContext, 182, OpenSearchPPLParser.RULE_comparisonOperator); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 930; + _la = this.tokenStream.LA(1); + if(!(_la === 67 || ((((_la - 112)) & ~0x1F) === 0 && ((1 << (_la - 112)) & 63) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public singleFieldRelevanceFunctionName(): SingleFieldRelevanceFunctionNameContext { + let localContext = new SingleFieldRelevanceFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 184, OpenSearchPPLParser.RULE_singleFieldRelevanceFunctionName); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 932; + _la = this.tokenStream.LA(1); + if(!(((((_la - 282)) & ~0x1F) === 0 && ((1 << (_la - 282)) & 15) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public multiFieldRelevanceFunctionName(): MultiFieldRelevanceFunctionNameContext { + let localContext = new MultiFieldRelevanceFunctionNameContext(this.context, this.state); + this.enterRule(localContext, 186, OpenSearchPPLParser.RULE_multiFieldRelevanceFunctionName); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 934; + _la = this.tokenStream.LA(1); + if(!(((((_la - 286)) & ~0x1F) === 0 && ((1 << (_la - 286)) & 7) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public literalValue(): LiteralValueContext { + let localContext = new LiteralValueContext(this.context, this.state); + this.enterRule(localContext, 188, OpenSearchPPLParser.RULE_literalValue); + try { + this.state = 942; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 71, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 936; + this.intervalLiteral(); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 937; + this.stringLiteral(); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 938; + this.integerLiteral(); + } + break; + case 4: + this.enterOuterAlt(localContext, 4); + { + this.state = 939; + this.decimalLiteral(); + } + break; + case 5: + this.enterOuterAlt(localContext, 5); + { + this.state = 940; + this.booleanLiteral(); + } + break; + case 6: + this.enterOuterAlt(localContext, 6); + { + this.state = 941; + this.datetimeLiteral(); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public intervalLiteral(): IntervalLiteralContext { + let localContext = new IntervalLiteralContext(this.context, this.state); + this.enterRule(localContext, 190, OpenSearchPPLParser.RULE_intervalLiteral); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 944; + this.match(OpenSearchPPLParser.INTERVAL); + this.state = 945; + this.valueExpression(0); + this.state = 946; + this.intervalUnit(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public stringLiteral(): StringLiteralContext { + let localContext = new StringLiteralContext(this.context, this.state); + this.enterRule(localContext, 192, OpenSearchPPLParser.RULE_stringLiteral); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 948; + _la = this.tokenStream.LA(1); + if(!(_la === 333 || _la === 334)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public integerLiteral(): IntegerLiteralContext { + let localContext = new IntegerLiteralContext(this.context, this.state); + this.enterRule(localContext, 194, OpenSearchPPLParser.RULE_integerLiteral); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 951; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 118 || _la === 119) { + { + this.state = 950; + _la = this.tokenStream.LA(1); + if(!(_la === 118 || _la === 119)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + + this.state = 953; + this.match(OpenSearchPPLParser.INTEGER_LITERAL); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public decimalLiteral(): DecimalLiteralContext { + let localContext = new DecimalLiteralContext(this.context, this.state); + this.enterRule(localContext, 196, OpenSearchPPLParser.RULE_decimalLiteral); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 956; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 118 || _la === 119) { + { + this.state = 955; + _la = this.tokenStream.LA(1); + if(!(_la === 118 || _la === 119)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + + this.state = 958; + this.match(OpenSearchPPLParser.DECIMAL_LITERAL); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public booleanLiteral(): BooleanLiteralContext { + let localContext = new BooleanLiteralContext(this.context, this.state); + this.enterRule(localContext, 198, OpenSearchPPLParser.RULE_booleanLiteral); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 960; + _la = this.tokenStream.LA(1); + if(!(_la === 65 || _la === 66)) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public datetimeLiteral(): DatetimeLiteralContext { + let localContext = new DatetimeLiteralContext(this.context, this.state); + this.enterRule(localContext, 200, OpenSearchPPLParser.RULE_datetimeLiteral); + try { + this.state = 965; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.DATE: + this.enterOuterAlt(localContext, 1); + { + this.state = 962; + this.dateLiteral(); + } + break; + case OpenSearchPPLParser.TIME: + this.enterOuterAlt(localContext, 2); + { + this.state = 963; + this.timeLiteral(); + } + break; + case OpenSearchPPLParser.TIMESTAMP: + this.enterOuterAlt(localContext, 3); + { + this.state = 964; + this.timestampLiteral(); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public dateLiteral(): DateLiteralContext { + let localContext = new DateLiteralContext(this.context, this.state); + this.enterRule(localContext, 202, OpenSearchPPLParser.RULE_dateLiteral); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 967; + this.match(OpenSearchPPLParser.DATE); + this.state = 968; + localContext._date = this.stringLiteral(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public timeLiteral(): TimeLiteralContext { + let localContext = new TimeLiteralContext(this.context, this.state); + this.enterRule(localContext, 204, OpenSearchPPLParser.RULE_timeLiteral); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 970; + this.match(OpenSearchPPLParser.TIME); + this.state = 971; + localContext._time = this.stringLiteral(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public timestampLiteral(): TimestampLiteralContext { + let localContext = new TimestampLiteralContext(this.context, this.state); + this.enterRule(localContext, 206, OpenSearchPPLParser.RULE_timestampLiteral); + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 973; + this.match(OpenSearchPPLParser.TIMESTAMP); + this.state = 974; + localContext._timestamp = this.stringLiteral(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public intervalUnit(): IntervalUnitContext { + let localContext = new IntervalUnitContext(this.context, this.state); + this.enterRule(localContext, 208, OpenSearchPPLParser.RULE_intervalUnit); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 976; + _la = this.tokenStream.LA(1); + if(!(((((_la - 70)) & ~0x1F) === 0 && ((1 << (_la - 70)) & 451728879) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public timespanUnit(): TimespanUnitContext { + let localContext = new TimespanUnitContext(this.context, this.state); + this.enterRule(localContext, 210, OpenSearchPPLParser.RULE_timespanUnit); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 978; + _la = this.tokenStream.LA(1); + if(!(_la === 31 || ((((_la - 70)) & ~0x1F) === 0 && ((1 << (_la - 70)) & 174612545) !== 0) || ((((_la - 321)) & ~0x1F) === 0 && ((1 << (_la - 321)) & 127) !== 0))) { + this.errorHandler.recoverInline(this); + } + else { + this.errorHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public valueList(): ValueListContext { + let localContext = new ValueListContext(this.context, this.state); + this.enterRule(localContext, 212, OpenSearchPPLParser.RULE_valueList); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 980; + this.match(OpenSearchPPLParser.LT_PRTHS); + this.state = 981; + this.literalValue(); + this.state = 986; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 110) { + { + { + this.state = 982; + this.match(OpenSearchPPLParser.COMMA); + this.state = 983; + this.literalValue(); + } + } + this.state = 988; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + this.state = 989; + this.match(OpenSearchPPLParser.RT_PRTHS); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public qualifiedName(): QualifiedNameContext { + let localContext = new QualifiedNameContext(this.context, this.state); + this.enterRule(localContext, 214, OpenSearchPPLParser.RULE_qualifiedName); + try { + let alternative: number; + localContext = new IdentsAsQualifiedNameContext(localContext); + this.enterOuterAlt(localContext, 1); + { + this.state = 991; + this.ident(); + this.state = 996; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 76, this.context); + while (alternative !== 2 && alternative !== antlr.ATN.INVALID_ALT_NUMBER) { + if (alternative === 1) { + { + { + this.state = 992; + this.match(OpenSearchPPLParser.DOT); + this.state = 993; + this.ident(); + } + } + } + this.state = 998; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 76, this.context); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public tableQualifiedName(): TableQualifiedNameContext { + let localContext = new TableQualifiedNameContext(this.context, this.state); + this.enterRule(localContext, 216, OpenSearchPPLParser.RULE_tableQualifiedName); + try { + let alternative: number; + localContext = new IdentsAsTableQualifiedNameContext(localContext); + this.enterOuterAlt(localContext, 1); + { + this.state = 999; + this.tableIdent(); + this.state = 1004; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 77, this.context); + while (alternative !== 2 && alternative !== antlr.ATN.INVALID_ALT_NUMBER) { + if (alternative === 1) { + { + { + this.state = 1000; + this.match(OpenSearchPPLParser.DOT); + this.state = 1001; + this.ident(); + } + } + } + this.state = 1006; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 77, this.context); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public wcQualifiedName(): WcQualifiedNameContext { + let localContext = new WcQualifiedNameContext(this.context, this.state); + this.enterRule(localContext, 218, OpenSearchPPLParser.RULE_wcQualifiedName); + let _la: number; + try { + localContext = new IdentsAsWildcardQualifiedNameContext(localContext); + this.enterOuterAlt(localContext, 1); + { + this.state = 1007; + this.wildcard(); + this.state = 1012; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + while (_la === 111) { + { + { + this.state = 1008; + this.match(OpenSearchPPLParser.DOT); + this.state = 1009; + this.wildcard(); + } + } + this.state = 1014; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + } + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public ident(): IdentContext { + let localContext = new IdentContext(this.context, this.state); + this.enterRule(localContext, 220, OpenSearchPPLParser.RULE_ident); + let _la: number; + try { + this.state = 1025; + this.errorHandler.sync(this); + switch (this.tokenStream.LA(1)) { + case OpenSearchPPLParser.DOT: + case OpenSearchPPLParser.ID: + this.enterOuterAlt(localContext, 1); + { + this.state = 1016; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 111) { + { + this.state = 1015; + this.match(OpenSearchPPLParser.DOT); + } + } + + this.state = 1018; + this.match(OpenSearchPPLParser.ID); + } + break; + case OpenSearchPPLParser.BACKTICK: + this.enterOuterAlt(localContext, 2); + { + this.state = 1019; + this.match(OpenSearchPPLParser.BACKTICK); + this.state = 1020; + this.ident(); + this.state = 1021; + this.match(OpenSearchPPLParser.BACKTICK); + } + break; + case OpenSearchPPLParser.BQUOTA_STRING: + this.enterOuterAlt(localContext, 3); + { + this.state = 1023; + this.match(OpenSearchPPLParser.BQUOTA_STRING); + } + break; + case OpenSearchPPLParser.SEARCH: + case OpenSearchPPLParser.DESCRIBE: + case OpenSearchPPLParser.SHOW: + case OpenSearchPPLParser.FROM: + case OpenSearchPPLParser.WHERE: + case OpenSearchPPLParser.FIELDS: + case OpenSearchPPLParser.RENAME: + case OpenSearchPPLParser.STATS: + case OpenSearchPPLParser.DEDUP: + case OpenSearchPPLParser.SORT: + case OpenSearchPPLParser.EVAL: + case OpenSearchPPLParser.HEAD: + case OpenSearchPPLParser.TOP: + case OpenSearchPPLParser.RARE: + case OpenSearchPPLParser.PARSE: + case OpenSearchPPLParser.METHOD: + case OpenSearchPPLParser.REGEX: + case OpenSearchPPLParser.PUNCT: + case OpenSearchPPLParser.GROK: + case OpenSearchPPLParser.PATTERN: + case OpenSearchPPLParser.PATTERNS: + case OpenSearchPPLParser.NEW_FIELD: + case OpenSearchPPLParser.KMEANS: + case OpenSearchPPLParser.AD: + case OpenSearchPPLParser.ML: + case OpenSearchPPLParser.SOURCE: + case OpenSearchPPLParser.INDEX: + case OpenSearchPPLParser.D: + case OpenSearchPPLParser.DESC: + case OpenSearchPPLParser.DATASOURCES: + case OpenSearchPPLParser.SORTBY: + case OpenSearchPPLParser.STR: + case OpenSearchPPLParser.IP: + case OpenSearchPPLParser.NUM: + case OpenSearchPPLParser.KEEPEMPTY: + case OpenSearchPPLParser.CONSECUTIVE: + case OpenSearchPPLParser.DEDUP_SPLITVALUES: + case OpenSearchPPLParser.PARTITIONS: + case OpenSearchPPLParser.ALLNUM: + case OpenSearchPPLParser.DELIM: + case OpenSearchPPLParser.CENTROIDS: + case OpenSearchPPLParser.ITERATIONS: + case OpenSearchPPLParser.DISTANCE_TYPE: + case OpenSearchPPLParser.NUMBER_OF_TREES: + case OpenSearchPPLParser.SHINGLE_SIZE: + case OpenSearchPPLParser.SAMPLE_SIZE: + case OpenSearchPPLParser.OUTPUT_AFTER: + case OpenSearchPPLParser.TIME_DECAY: + case OpenSearchPPLParser.ANOMALY_RATE: + case OpenSearchPPLParser.CATEGORY_FIELD: + case OpenSearchPPLParser.TIME_FIELD: + case OpenSearchPPLParser.TIME_ZONE: + case OpenSearchPPLParser.TRAINING_DATA_SIZE: + case OpenSearchPPLParser.ANOMALY_SCORE_THRESHOLD: + case OpenSearchPPLParser.CONVERT_TZ: + case OpenSearchPPLParser.DATETIME: + case OpenSearchPPLParser.DAY: + case OpenSearchPPLParser.DAY_HOUR: + case OpenSearchPPLParser.DAY_MICROSECOND: + case OpenSearchPPLParser.DAY_MINUTE: + case OpenSearchPPLParser.DAY_OF_YEAR: + case OpenSearchPPLParser.DAY_SECOND: + case OpenSearchPPLParser.HOUR: + case OpenSearchPPLParser.HOUR_MICROSECOND: + case OpenSearchPPLParser.HOUR_MINUTE: + case OpenSearchPPLParser.HOUR_OF_DAY: + case OpenSearchPPLParser.HOUR_SECOND: + case OpenSearchPPLParser.MICROSECOND: + case OpenSearchPPLParser.MILLISECOND: + case OpenSearchPPLParser.MINUTE: + case OpenSearchPPLParser.MINUTE_MICROSECOND: + case OpenSearchPPLParser.MINUTE_OF_DAY: + case OpenSearchPPLParser.MINUTE_OF_HOUR: + case OpenSearchPPLParser.MINUTE_SECOND: + case OpenSearchPPLParser.MONTH: + case OpenSearchPPLParser.MONTH_OF_YEAR: + case OpenSearchPPLParser.QUARTER: + case OpenSearchPPLParser.SECOND: + case OpenSearchPPLParser.SECOND_MICROSECOND: + case OpenSearchPPLParser.SECOND_OF_MINUTE: + case OpenSearchPPLParser.WEEK: + case OpenSearchPPLParser.WEEK_OF_YEAR: + case OpenSearchPPLParser.YEAR: + case OpenSearchPPLParser.YEAR_MONTH: + case OpenSearchPPLParser.AVG: + case OpenSearchPPLParser.COUNT: + case OpenSearchPPLParser.DISTINCT_COUNT: + case OpenSearchPPLParser.ESTDC: + case OpenSearchPPLParser.ESTDC_ERROR: + case OpenSearchPPLParser.MAX: + case OpenSearchPPLParser.MEAN: + case OpenSearchPPLParser.MEDIAN: + case OpenSearchPPLParser.MIN: + case OpenSearchPPLParser.MODE: + case OpenSearchPPLParser.RANGE: + case OpenSearchPPLParser.STDEV: + case OpenSearchPPLParser.STDEVP: + case OpenSearchPPLParser.SUM: + case OpenSearchPPLParser.SUMSQ: + case OpenSearchPPLParser.VAR_SAMP: + case OpenSearchPPLParser.VAR_POP: + case OpenSearchPPLParser.STDDEV_SAMP: + case OpenSearchPPLParser.STDDEV_POP: + case OpenSearchPPLParser.PERCENTILE: + case OpenSearchPPLParser.TAKE: + case OpenSearchPPLParser.FIRST: + case OpenSearchPPLParser.LAST: + case OpenSearchPPLParser.LIST: + case OpenSearchPPLParser.VALUES: + case OpenSearchPPLParser.EARLIEST: + case OpenSearchPPLParser.EARLIEST_TIME: + case OpenSearchPPLParser.LATEST: + case OpenSearchPPLParser.LATEST_TIME: + case OpenSearchPPLParser.PER_DAY: + case OpenSearchPPLParser.PER_HOUR: + case OpenSearchPPLParser.PER_MINUTE: + case OpenSearchPPLParser.PER_SECOND: + case OpenSearchPPLParser.RATE: + case OpenSearchPPLParser.SPARKLINE: + case OpenSearchPPLParser.C: + case OpenSearchPPLParser.DC: + case OpenSearchPPLParser.ABS: + case OpenSearchPPLParser.CBRT: + case OpenSearchPPLParser.CEIL: + case OpenSearchPPLParser.CEILING: + case OpenSearchPPLParser.CONV: + case OpenSearchPPLParser.CRC32: + case OpenSearchPPLParser.E: + case OpenSearchPPLParser.EXP: + case OpenSearchPPLParser.FLOOR: + case OpenSearchPPLParser.LN: + case OpenSearchPPLParser.LOG: + case OpenSearchPPLParser.LOG10: + case OpenSearchPPLParser.LOG2: + case OpenSearchPPLParser.MOD: + case OpenSearchPPLParser.PI: + case OpenSearchPPLParser.POSITION: + case OpenSearchPPLParser.POW: + case OpenSearchPPLParser.POWER: + case OpenSearchPPLParser.RAND: + case OpenSearchPPLParser.ROUND: + case OpenSearchPPLParser.SIGN: + case OpenSearchPPLParser.SQRT: + case OpenSearchPPLParser.TRUNCATE: + case OpenSearchPPLParser.ACOS: + case OpenSearchPPLParser.ASIN: + case OpenSearchPPLParser.ATAN: + case OpenSearchPPLParser.ATAN2: + case OpenSearchPPLParser.COS: + case OpenSearchPPLParser.COT: + case OpenSearchPPLParser.DEGREES: + case OpenSearchPPLParser.RADIANS: + case OpenSearchPPLParser.SIN: + case OpenSearchPPLParser.TAN: + case OpenSearchPPLParser.ADDDATE: + case OpenSearchPPLParser.ADDTIME: + case OpenSearchPPLParser.CURDATE: + case OpenSearchPPLParser.CURRENT_DATE: + case OpenSearchPPLParser.CURRENT_TIME: + case OpenSearchPPLParser.CURRENT_TIMESTAMP: + case OpenSearchPPLParser.CURTIME: + case OpenSearchPPLParser.DATE: + case OpenSearchPPLParser.DATEDIFF: + case OpenSearchPPLParser.DATE_ADD: + case OpenSearchPPLParser.DATE_FORMAT: + case OpenSearchPPLParser.DATE_SUB: + case OpenSearchPPLParser.DAYNAME: + case OpenSearchPPLParser.DAYOFMONTH: + case OpenSearchPPLParser.DAYOFWEEK: + case OpenSearchPPLParser.DAYOFYEAR: + case OpenSearchPPLParser.DAY_OF_MONTH: + case OpenSearchPPLParser.DAY_OF_WEEK: + case OpenSearchPPLParser.FROM_DAYS: + case OpenSearchPPLParser.FROM_UNIXTIME: + case OpenSearchPPLParser.LAST_DAY: + case OpenSearchPPLParser.LOCALTIME: + case OpenSearchPPLParser.LOCALTIMESTAMP: + case OpenSearchPPLParser.MAKEDATE: + case OpenSearchPPLParser.MAKETIME: + case OpenSearchPPLParser.MONTHNAME: + case OpenSearchPPLParser.NOW: + case OpenSearchPPLParser.PERIOD_ADD: + case OpenSearchPPLParser.PERIOD_DIFF: + case OpenSearchPPLParser.SEC_TO_TIME: + case OpenSearchPPLParser.STR_TO_DATE: + case OpenSearchPPLParser.SUBDATE: + case OpenSearchPPLParser.SUBTIME: + case OpenSearchPPLParser.SYSDATE: + case OpenSearchPPLParser.TIME: + case OpenSearchPPLParser.TIMEDIFF: + case OpenSearchPPLParser.TIMESTAMP: + case OpenSearchPPLParser.TIME_FORMAT: + case OpenSearchPPLParser.TIME_TO_SEC: + case OpenSearchPPLParser.TO_DAYS: + case OpenSearchPPLParser.TO_SECONDS: + case OpenSearchPPLParser.UNIX_TIMESTAMP: + case OpenSearchPPLParser.UTC_DATE: + case OpenSearchPPLParser.UTC_TIME: + case OpenSearchPPLParser.UTC_TIMESTAMP: + case OpenSearchPPLParser.WEEKDAY: + case OpenSearchPPLParser.YEARWEEK: + case OpenSearchPPLParser.SUBSTR: + case OpenSearchPPLParser.SUBSTRING: + case OpenSearchPPLParser.LTRIM: + case OpenSearchPPLParser.RTRIM: + case OpenSearchPPLParser.TRIM: + case OpenSearchPPLParser.LOWER: + case OpenSearchPPLParser.UPPER: + case OpenSearchPPLParser.CONCAT: + case OpenSearchPPLParser.CONCAT_WS: + case OpenSearchPPLParser.LENGTH: + case OpenSearchPPLParser.STRCMP: + case OpenSearchPPLParser.RIGHT: + case OpenSearchPPLParser.LEFT: + case OpenSearchPPLParser.ASCII: + case OpenSearchPPLParser.LOCATE: + case OpenSearchPPLParser.REPLACE: + case OpenSearchPPLParser.REVERSE: + case OpenSearchPPLParser.LIKE: + case OpenSearchPPLParser.ISNULL: + case OpenSearchPPLParser.ISNOTNULL: + case OpenSearchPPLParser.IFNULL: + case OpenSearchPPLParser.NULLIF: + case OpenSearchPPLParser.IF: + case OpenSearchPPLParser.TYPEOF: + case OpenSearchPPLParser.ALLOW_LEADING_WILDCARD: + case OpenSearchPPLParser.ANALYZE_WILDCARD: + case OpenSearchPPLParser.ANALYZER: + case OpenSearchPPLParser.AUTO_GENERATE_SYNONYMS_PHRASE_QUERY: + case OpenSearchPPLParser.BOOST: + case OpenSearchPPLParser.CUTOFF_FREQUENCY: + case OpenSearchPPLParser.DEFAULT_FIELD: + case OpenSearchPPLParser.DEFAULT_OPERATOR: + case OpenSearchPPLParser.ENABLE_POSITION_INCREMENTS: + case OpenSearchPPLParser.ESCAPE: + case OpenSearchPPLParser.FLAGS: + case OpenSearchPPLParser.FUZZY_MAX_EXPANSIONS: + case OpenSearchPPLParser.FUZZY_PREFIX_LENGTH: + case OpenSearchPPLParser.FUZZY_TRANSPOSITIONS: + case OpenSearchPPLParser.FUZZY_REWRITE: + case OpenSearchPPLParser.FUZZINESS: + case OpenSearchPPLParser.LENIENT: + case OpenSearchPPLParser.LOW_FREQ_OPERATOR: + case OpenSearchPPLParser.MAX_DETERMINIZED_STATES: + case OpenSearchPPLParser.MAX_EXPANSIONS: + case OpenSearchPPLParser.MINIMUM_SHOULD_MATCH: + case OpenSearchPPLParser.OPERATOR: + case OpenSearchPPLParser.PHRASE_SLOP: + case OpenSearchPPLParser.PREFIX_LENGTH: + case OpenSearchPPLParser.QUOTE_ANALYZER: + case OpenSearchPPLParser.QUOTE_FIELD_SUFFIX: + case OpenSearchPPLParser.REWRITE: + case OpenSearchPPLParser.SLOP: + case OpenSearchPPLParser.TIE_BREAKER: + case OpenSearchPPLParser.TYPE: + case OpenSearchPPLParser.ZERO_TERMS_QUERY: + case OpenSearchPPLParser.SPAN: + case OpenSearchPPLParser.MS: + case OpenSearchPPLParser.S: + case OpenSearchPPLParser.M: + case OpenSearchPPLParser.H: + case OpenSearchPPLParser.W: + case OpenSearchPPLParser.Q: + case OpenSearchPPLParser.Y: + this.enterOuterAlt(localContext, 4); + { + this.state = 1024; + this.keywordsCanBeId(); + } + break; + default: + throw new antlr.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public tableIdent(): TableIdentContext { + let localContext = new TableIdentContext(this.context, this.state); + this.enterRule(localContext, 222, OpenSearchPPLParser.RULE_tableIdent); + let _la: number; + try { + this.enterOuterAlt(localContext, 1); + { + this.state = 1028; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 329) { + { + this.state = 1027; + this.match(OpenSearchPPLParser.CLUSTER); + } + } + + this.state = 1030; + this.ident(); + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public wildcard(): WildcardContext { + let localContext = new WildcardContext(this.context, this.state); + this.enterRule(localContext, 224, OpenSearchPPLParser.RULE_wildcard); + let _la: number; + try { + let alternative: number; + this.state = 1055; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 84, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 1032; + this.ident(); + this.state = 1037; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 82, this.context); + while (alternative !== 2 && alternative !== antlr.ATN.INVALID_ALT_NUMBER) { + if (alternative === 1) { + { + { + this.state = 1033; + this.match(OpenSearchPPLParser.MODULE); + this.state = 1034; + this.ident(); + } + } + } + this.state = 1039; + this.errorHandler.sync(this); + alternative = this.interpreter.adaptivePredict(this.tokenStream, 82, this.context); + } + this.state = 1041; + this.errorHandler.sync(this); + _la = this.tokenStream.LA(1); + if (_la === 122) { + { + this.state = 1040; + this.match(OpenSearchPPLParser.MODULE); + } + } + + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 1043; + this.match(OpenSearchPPLParser.SINGLE_QUOTE); + this.state = 1044; + this.wildcard(); + this.state = 1045; + this.match(OpenSearchPPLParser.SINGLE_QUOTE); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 1047; + this.match(OpenSearchPPLParser.DOUBLE_QUOTE); + this.state = 1048; + this.wildcard(); + this.state = 1049; + this.match(OpenSearchPPLParser.DOUBLE_QUOTE); + } + break; + case 4: + this.enterOuterAlt(localContext, 4); + { + this.state = 1051; + this.match(OpenSearchPPLParser.BACKTICK); + this.state = 1052; + this.wildcard(); + this.state = 1053; + this.match(OpenSearchPPLParser.BACKTICK); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + public keywordsCanBeId(): KeywordsCanBeIdContext { + let localContext = new KeywordsCanBeIdContext(this.context, this.state); + this.enterRule(localContext, 226, OpenSearchPPLParser.RULE_keywordsCanBeId); + try { + this.state = 1157; + this.errorHandler.sync(this); + switch (this.interpreter.adaptivePredict(this.tokenStream, 85, this.context) ) { + case 1: + this.enterOuterAlt(localContext, 1); + { + this.state = 1057; + this.match(OpenSearchPPLParser.D); + } + break; + case 2: + this.enterOuterAlt(localContext, 2); + { + this.state = 1058; + this.timespanUnit(); + } + break; + case 3: + this.enterOuterAlt(localContext, 3); + { + this.state = 1059; + this.match(OpenSearchPPLParser.SPAN); + } + break; + case 4: + this.enterOuterAlt(localContext, 4); + { + this.state = 1060; + this.evalFunctionName(); + } + break; + case 5: + this.enterOuterAlt(localContext, 5); + { + this.state = 1061; + this.relevanceArgName(); + } + break; + case 6: + this.enterOuterAlt(localContext, 6); + { + this.state = 1062; + this.intervalUnit(); + } + break; + case 7: + this.enterOuterAlt(localContext, 7); + { + this.state = 1063; + this.dateTimeFunctionName(); + } + break; + case 8: + this.enterOuterAlt(localContext, 8); + { + this.state = 1064; + this.textFunctionName(); + } + break; + case 9: + this.enterOuterAlt(localContext, 9); + { + this.state = 1065; + this.mathematicalFunctionName(); + } + break; + case 10: + this.enterOuterAlt(localContext, 10); + { + this.state = 1066; + this.positionFunctionName(); + } + break; + case 11: + this.enterOuterAlt(localContext, 11); + { + this.state = 1067; + this.match(OpenSearchPPLParser.SEARCH); + } + break; + case 12: + this.enterOuterAlt(localContext, 12); + { + this.state = 1068; + this.match(OpenSearchPPLParser.DESCRIBE); + } + break; + case 13: + this.enterOuterAlt(localContext, 13); + { + this.state = 1069; + this.match(OpenSearchPPLParser.SHOW); + } + break; + case 14: + this.enterOuterAlt(localContext, 14); + { + this.state = 1070; + this.match(OpenSearchPPLParser.FROM); + } + break; + case 15: + this.enterOuterAlt(localContext, 15); + { + this.state = 1071; + this.match(OpenSearchPPLParser.WHERE); + } + break; + case 16: + this.enterOuterAlt(localContext, 16); + { + this.state = 1072; + this.match(OpenSearchPPLParser.FIELDS); + } + break; + case 17: + this.enterOuterAlt(localContext, 17); + { + this.state = 1073; + this.match(OpenSearchPPLParser.RENAME); + } + break; + case 18: + this.enterOuterAlt(localContext, 18); + { + this.state = 1074; + this.match(OpenSearchPPLParser.STATS); + } + break; + case 19: + this.enterOuterAlt(localContext, 19); + { + this.state = 1075; + this.match(OpenSearchPPLParser.DEDUP); + } + break; + case 20: + this.enterOuterAlt(localContext, 20); + { + this.state = 1076; + this.match(OpenSearchPPLParser.SORT); + } + break; + case 21: + this.enterOuterAlt(localContext, 21); + { + this.state = 1077; + this.match(OpenSearchPPLParser.EVAL); + } + break; + case 22: + this.enterOuterAlt(localContext, 22); + { + this.state = 1078; + this.match(OpenSearchPPLParser.HEAD); + } + break; + case 23: + this.enterOuterAlt(localContext, 23); + { + this.state = 1079; + this.match(OpenSearchPPLParser.TOP); + } + break; + case 24: + this.enterOuterAlt(localContext, 24); + { + this.state = 1080; + this.match(OpenSearchPPLParser.RARE); + } + break; + case 25: + this.enterOuterAlt(localContext, 25); + { + this.state = 1081; + this.match(OpenSearchPPLParser.PARSE); + } + break; + case 26: + this.enterOuterAlt(localContext, 26); + { + this.state = 1082; + this.match(OpenSearchPPLParser.METHOD); + } + break; + case 27: + this.enterOuterAlt(localContext, 27); + { + this.state = 1083; + this.match(OpenSearchPPLParser.REGEX); + } + break; + case 28: + this.enterOuterAlt(localContext, 28); + { + this.state = 1084; + this.match(OpenSearchPPLParser.PUNCT); + } + break; + case 29: + this.enterOuterAlt(localContext, 29); + { + this.state = 1085; + this.match(OpenSearchPPLParser.GROK); + } + break; + case 30: + this.enterOuterAlt(localContext, 30); + { + this.state = 1086; + this.match(OpenSearchPPLParser.PATTERN); + } + break; + case 31: + this.enterOuterAlt(localContext, 31); + { + this.state = 1087; + this.match(OpenSearchPPLParser.PATTERNS); + } + break; + case 32: + this.enterOuterAlt(localContext, 32); + { + this.state = 1088; + this.match(OpenSearchPPLParser.NEW_FIELD); + } + break; + case 33: + this.enterOuterAlt(localContext, 33); + { + this.state = 1089; + this.match(OpenSearchPPLParser.KMEANS); + } + break; + case 34: + this.enterOuterAlt(localContext, 34); + { + this.state = 1090; + this.match(OpenSearchPPLParser.AD); + } + break; + case 35: + this.enterOuterAlt(localContext, 35); + { + this.state = 1091; + this.match(OpenSearchPPLParser.ML); + } + break; + case 36: + this.enterOuterAlt(localContext, 36); + { + this.state = 1092; + this.match(OpenSearchPPLParser.SOURCE); + } + break; + case 37: + this.enterOuterAlt(localContext, 37); + { + this.state = 1093; + this.match(OpenSearchPPLParser.INDEX); + } + break; + case 38: + this.enterOuterAlt(localContext, 38); + { + this.state = 1094; + this.match(OpenSearchPPLParser.DESC); + } + break; + case 39: + this.enterOuterAlt(localContext, 39); + { + this.state = 1095; + this.match(OpenSearchPPLParser.DATASOURCES); + } + break; + case 40: + this.enterOuterAlt(localContext, 40); + { + this.state = 1096; + this.match(OpenSearchPPLParser.SORTBY); + } + break; + case 41: + this.enterOuterAlt(localContext, 41); + { + this.state = 1097; + this.match(OpenSearchPPLParser.STR); + } + break; + case 42: + this.enterOuterAlt(localContext, 42); + { + this.state = 1098; + this.match(OpenSearchPPLParser.IP); + } + break; + case 43: + this.enterOuterAlt(localContext, 43); + { + this.state = 1099; + this.match(OpenSearchPPLParser.NUM); + } + break; + case 44: + this.enterOuterAlt(localContext, 44); + { + this.state = 1100; + this.match(OpenSearchPPLParser.KEEPEMPTY); + } + break; + case 45: + this.enterOuterAlt(localContext, 45); + { + this.state = 1101; + this.match(OpenSearchPPLParser.CONSECUTIVE); + } + break; + case 46: + this.enterOuterAlt(localContext, 46); + { + this.state = 1102; + this.match(OpenSearchPPLParser.DEDUP_SPLITVALUES); + } + break; + case 47: + this.enterOuterAlt(localContext, 47); + { + this.state = 1103; + this.match(OpenSearchPPLParser.PARTITIONS); + } + break; + case 48: + this.enterOuterAlt(localContext, 48); + { + this.state = 1104; + this.match(OpenSearchPPLParser.ALLNUM); + } + break; + case 49: + this.enterOuterAlt(localContext, 49); + { + this.state = 1105; + this.match(OpenSearchPPLParser.DELIM); + } + break; + case 50: + this.enterOuterAlt(localContext, 50); + { + this.state = 1106; + this.match(OpenSearchPPLParser.CENTROIDS); + } + break; + case 51: + this.enterOuterAlt(localContext, 51); + { + this.state = 1107; + this.match(OpenSearchPPLParser.ITERATIONS); + } + break; + case 52: + this.enterOuterAlt(localContext, 52); + { + this.state = 1108; + this.match(OpenSearchPPLParser.DISTANCE_TYPE); + } + break; + case 53: + this.enterOuterAlt(localContext, 53); + { + this.state = 1109; + this.match(OpenSearchPPLParser.NUMBER_OF_TREES); + } + break; + case 54: + this.enterOuterAlt(localContext, 54); + { + this.state = 1110; + this.match(OpenSearchPPLParser.SHINGLE_SIZE); + } + break; + case 55: + this.enterOuterAlt(localContext, 55); + { + this.state = 1111; + this.match(OpenSearchPPLParser.SAMPLE_SIZE); + } + break; + case 56: + this.enterOuterAlt(localContext, 56); + { + this.state = 1112; + this.match(OpenSearchPPLParser.OUTPUT_AFTER); + } + break; + case 57: + this.enterOuterAlt(localContext, 57); + { + this.state = 1113; + this.match(OpenSearchPPLParser.TIME_DECAY); + } + break; + case 58: + this.enterOuterAlt(localContext, 58); + { + this.state = 1114; + this.match(OpenSearchPPLParser.ANOMALY_RATE); + } + break; + case 59: + this.enterOuterAlt(localContext, 59); + { + this.state = 1115; + this.match(OpenSearchPPLParser.CATEGORY_FIELD); + } + break; + case 60: + this.enterOuterAlt(localContext, 60); + { + this.state = 1116; + this.match(OpenSearchPPLParser.TIME_FIELD); + } + break; + case 61: + this.enterOuterAlt(localContext, 61); + { + this.state = 1117; + this.match(OpenSearchPPLParser.TIME_ZONE); + } + break; + case 62: + this.enterOuterAlt(localContext, 62); + { + this.state = 1118; + this.match(OpenSearchPPLParser.TRAINING_DATA_SIZE); + } + break; + case 63: + this.enterOuterAlt(localContext, 63); + { + this.state = 1119; + this.match(OpenSearchPPLParser.ANOMALY_SCORE_THRESHOLD); + } + break; + case 64: + this.enterOuterAlt(localContext, 64); + { + this.state = 1120; + this.match(OpenSearchPPLParser.AVG); + } + break; + case 65: + this.enterOuterAlt(localContext, 65); + { + this.state = 1121; + this.match(OpenSearchPPLParser.COUNT); + } + break; + case 66: + this.enterOuterAlt(localContext, 66); + { + this.state = 1122; + this.match(OpenSearchPPLParser.DISTINCT_COUNT); + } + break; + case 67: + this.enterOuterAlt(localContext, 67); + { + this.state = 1123; + this.match(OpenSearchPPLParser.ESTDC); + } + break; + case 68: + this.enterOuterAlt(localContext, 68); + { + this.state = 1124; + this.match(OpenSearchPPLParser.ESTDC_ERROR); + } + break; + case 69: + this.enterOuterAlt(localContext, 69); + { + this.state = 1125; + this.match(OpenSearchPPLParser.MAX); + } + break; + case 70: + this.enterOuterAlt(localContext, 70); + { + this.state = 1126; + this.match(OpenSearchPPLParser.MEAN); + } + break; + case 71: + this.enterOuterAlt(localContext, 71); + { + this.state = 1127; + this.match(OpenSearchPPLParser.MEDIAN); + } + break; + case 72: + this.enterOuterAlt(localContext, 72); + { + this.state = 1128; + this.match(OpenSearchPPLParser.MIN); + } + break; + case 73: + this.enterOuterAlt(localContext, 73); + { + this.state = 1129; + this.match(OpenSearchPPLParser.MODE); + } + break; + case 74: + this.enterOuterAlt(localContext, 74); + { + this.state = 1130; + this.match(OpenSearchPPLParser.RANGE); + } + break; + case 75: + this.enterOuterAlt(localContext, 75); + { + this.state = 1131; + this.match(OpenSearchPPLParser.STDEV); + } + break; + case 76: + this.enterOuterAlt(localContext, 76); + { + this.state = 1132; + this.match(OpenSearchPPLParser.STDEVP); + } + break; + case 77: + this.enterOuterAlt(localContext, 77); + { + this.state = 1133; + this.match(OpenSearchPPLParser.SUM); + } + break; + case 78: + this.enterOuterAlt(localContext, 78); + { + this.state = 1134; + this.match(OpenSearchPPLParser.SUMSQ); + } + break; + case 79: + this.enterOuterAlt(localContext, 79); + { + this.state = 1135; + this.match(OpenSearchPPLParser.VAR_SAMP); + } + break; + case 80: + this.enterOuterAlt(localContext, 80); + { + this.state = 1136; + this.match(OpenSearchPPLParser.VAR_POP); + } + break; + case 81: + this.enterOuterAlt(localContext, 81); + { + this.state = 1137; + this.match(OpenSearchPPLParser.STDDEV_SAMP); + } + break; + case 82: + this.enterOuterAlt(localContext, 82); + { + this.state = 1138; + this.match(OpenSearchPPLParser.STDDEV_POP); + } + break; + case 83: + this.enterOuterAlt(localContext, 83); + { + this.state = 1139; + this.match(OpenSearchPPLParser.PERCENTILE); + } + break; + case 84: + this.enterOuterAlt(localContext, 84); + { + this.state = 1140; + this.match(OpenSearchPPLParser.TAKE); + } + break; + case 85: + this.enterOuterAlt(localContext, 85); + { + this.state = 1141; + this.match(OpenSearchPPLParser.FIRST); + } + break; + case 86: + this.enterOuterAlt(localContext, 86); + { + this.state = 1142; + this.match(OpenSearchPPLParser.LAST); + } + break; + case 87: + this.enterOuterAlt(localContext, 87); + { + this.state = 1143; + this.match(OpenSearchPPLParser.LIST); + } + break; + case 88: + this.enterOuterAlt(localContext, 88); + { + this.state = 1144; + this.match(OpenSearchPPLParser.VALUES); + } + break; + case 89: + this.enterOuterAlt(localContext, 89); + { + this.state = 1145; + this.match(OpenSearchPPLParser.EARLIEST); + } + break; + case 90: + this.enterOuterAlt(localContext, 90); + { + this.state = 1146; + this.match(OpenSearchPPLParser.EARLIEST_TIME); + } + break; + case 91: + this.enterOuterAlt(localContext, 91); + { + this.state = 1147; + this.match(OpenSearchPPLParser.LATEST); + } + break; + case 92: + this.enterOuterAlt(localContext, 92); + { + this.state = 1148; + this.match(OpenSearchPPLParser.LATEST_TIME); + } + break; + case 93: + this.enterOuterAlt(localContext, 93); + { + this.state = 1149; + this.match(OpenSearchPPLParser.PER_DAY); + } + break; + case 94: + this.enterOuterAlt(localContext, 94); + { + this.state = 1150; + this.match(OpenSearchPPLParser.PER_HOUR); + } + break; + case 95: + this.enterOuterAlt(localContext, 95); + { + this.state = 1151; + this.match(OpenSearchPPLParser.PER_MINUTE); + } + break; + case 96: + this.enterOuterAlt(localContext, 96); + { + this.state = 1152; + this.match(OpenSearchPPLParser.PER_SECOND); + } + break; + case 97: + this.enterOuterAlt(localContext, 97); + { + this.state = 1153; + this.match(OpenSearchPPLParser.RATE); + } + break; + case 98: + this.enterOuterAlt(localContext, 98); + { + this.state = 1154; + this.match(OpenSearchPPLParser.SPARKLINE); + } + break; + case 99: + this.enterOuterAlt(localContext, 99); + { + this.state = 1155; + this.match(OpenSearchPPLParser.C); + } + break; + case 100: + this.enterOuterAlt(localContext, 100); + { + this.state = 1156; + this.match(OpenSearchPPLParser.DC); + } + break; + } + } + catch (re) { + if (re instanceof antlr.RecognitionException) { + this.errorHandler.reportError(this, re); + this.errorHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return localContext; + } + + public override sempred(localContext: antlr.ParserRuleContext | null, ruleIndex: number, predIndex: number): boolean { + switch (ruleIndex) { + case 45: + return this.logicalExpression_sempred(localContext as LogicalExpressionContext, predIndex); + case 47: + return this.valueExpression_sempred(localContext as ValueExpressionContext, predIndex); + } + return true; + } + private logicalExpression_sempred(localContext: LogicalExpressionContext | null, predIndex: number): boolean { + switch (predIndex) { + case 0: + return this.precpred(this.context, 5); + case 1: + return this.precpred(this.context, 4); + case 2: + return this.precpred(this.context, 3); + } + return true; + } + private valueExpression_sempred(localContext: ValueExpressionContext | null, predIndex: number): boolean { + switch (predIndex) { + case 3: + return this.precpred(this.context, 8); + case 4: + return this.precpred(this.context, 7); + } + return true; + } + + public static readonly _serializedATN: number[] = [ + 4,1,336,1160,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6, + 7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7, + 13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2, + 20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7, + 26,2,27,7,27,2,28,7,28,2,29,7,29,2,30,7,30,2,31,7,31,2,32,7,32,2, + 33,7,33,2,34,7,34,2,35,7,35,2,36,7,36,2,37,7,37,2,38,7,38,2,39,7, + 39,2,40,7,40,2,41,7,41,2,42,7,42,2,43,7,43,2,44,7,44,2,45,7,45,2, + 46,7,46,2,47,7,47,2,48,7,48,2,49,7,49,2,50,7,50,2,51,7,51,2,52,7, + 52,2,53,7,53,2,54,7,54,2,55,7,55,2,56,7,56,2,57,7,57,2,58,7,58,2, + 59,7,59,2,60,7,60,2,61,7,61,2,62,7,62,2,63,7,63,2,64,7,64,2,65,7, + 65,2,66,7,66,2,67,7,67,2,68,7,68,2,69,7,69,2,70,7,70,2,71,7,71,2, + 72,7,72,2,73,7,73,2,74,7,74,2,75,7,75,2,76,7,76,2,77,7,77,2,78,7, + 78,2,79,7,79,2,80,7,80,2,81,7,81,2,82,7,82,2,83,7,83,2,84,7,84,2, + 85,7,85,2,86,7,86,2,87,7,87,2,88,7,88,2,89,7,89,2,90,7,90,2,91,7, + 91,2,92,7,92,2,93,7,93,2,94,7,94,2,95,7,95,2,96,7,96,2,97,7,97,2, + 98,7,98,2,99,7,99,2,100,7,100,2,101,7,101,2,102,7,102,2,103,7,103, + 2,104,7,104,2,105,7,105,2,106,7,106,2,107,7,107,2,108,7,108,2,109, + 7,109,2,110,7,110,2,111,7,111,2,112,7,112,2,113,7,113,1,0,3,0,230, + 8,0,1,0,1,0,1,1,1,1,1,2,1,2,1,3,1,3,1,3,5,3,241,8,3,10,3,12,3,244, + 9,3,1,4,1,4,1,4,3,4,249,8,4,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,5, + 1,5,1,5,1,5,1,5,1,5,1,5,1,5,3,5,267,8,5,1,6,3,6,270,8,6,1,6,1,6, + 3,6,274,8,6,1,6,1,6,1,6,1,6,3,6,280,8,6,1,6,1,6,1,6,3,6,285,8,6, + 1,7,1,7,1,7,1,8,1,8,1,8,1,9,1,9,1,9,1,10,1,10,3,10,298,8,10,1,10, + 1,10,1,11,1,11,1,11,1,11,5,11,306,8,11,10,11,12,11,309,9,11,1,12, + 1,12,1,12,1,12,3,12,315,8,12,1,12,1,12,1,12,3,12,320,8,12,1,12,1, + 12,1,12,3,12,325,8,12,1,12,1,12,1,12,5,12,330,8,12,10,12,12,12,333, + 9,12,1,12,3,12,336,8,12,1,12,1,12,1,12,3,12,341,8,12,1,13,1,13,3, + 13,345,8,13,1,13,1,13,1,13,1,13,3,13,351,8,13,1,13,1,13,1,13,3,13, + 356,8,13,1,14,1,14,1,14,1,15,1,15,1,15,1,15,5,15,365,8,15,10,15, + 12,15,368,9,15,1,16,1,16,3,16,372,8,16,1,16,1,16,3,16,376,8,16,1, + 17,1,17,3,17,380,8,17,1,17,1,17,3,17,384,8,17,1,18,1,18,1,18,3,18, + 389,8,18,1,19,1,19,1,19,1,19,1,20,1,20,1,20,1,20,1,21,1,21,5,21, + 401,8,21,10,21,12,21,404,9,21,1,21,1,21,1,22,1,22,1,22,1,22,1,22, + 1,22,3,22,414,8,22,1,23,1,23,1,24,1,24,5,24,420,8,24,10,24,12,24, + 423,9,24,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,1,25,3,25,434,8, + 25,1,26,1,26,5,26,438,8,26,10,26,12,26,441,9,26,1,27,1,27,1,27,1, + 27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1, + 27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1,27,1, + 27,1,27,1,27,1,27,1,27,1,27,1,27,3,27,479,8,27,1,28,1,28,5,28,483, + 8,28,10,28,12,28,486,9,28,1,29,1,29,1,29,1,29,1,30,1,30,1,30,1,30, + 1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,30,3,30,504,8,30,1,31,1,31, + 1,31,5,31,509,8,31,10,31,12,31,512,9,31,1,32,1,32,1,32,1,32,1,33, + 1,33,1,33,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,3,34,530, + 8,34,1,35,1,35,1,35,3,35,535,8,35,1,36,1,36,1,36,1,36,1,36,1,36, + 3,36,543,8,36,1,36,1,36,1,37,1,37,1,37,5,37,550,8,37,10,37,12,37, + 553,9,37,1,38,1,38,1,38,1,38,1,39,1,39,1,39,3,39,562,8,39,1,40,1, + 40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1, + 40,3,40,579,8,40,1,41,1,41,1,42,1,42,1,42,1,42,1,42,3,42,588,8,42, + 1,42,1,42,1,43,1,43,1,43,1,43,1,43,1,43,1,43,1,43,1,44,1,44,1,44, + 3,44,603,8,44,1,45,1,45,1,45,1,45,1,45,1,45,3,45,611,8,45,1,45,1, + 45,1,45,1,45,1,45,3,45,618,8,45,1,45,1,45,1,45,1,45,5,45,624,8,45, + 10,45,12,45,627,9,45,1,46,1,46,1,46,1,46,1,46,1,46,1,46,1,46,3,46, + 637,8,46,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,3,47, + 649,8,47,1,47,1,47,1,47,1,47,1,47,1,47,5,47,657,8,47,10,47,12,47, + 660,9,47,1,48,1,48,1,48,1,48,3,48,666,8,48,1,49,1,49,1,49,1,49,1, + 49,1,49,1,49,1,50,1,50,1,51,1,51,3,51,679,8,51,1,52,1,52,1,52,1, + 52,1,52,1,52,1,52,5,52,688,8,52,10,52,12,52,691,9,52,1,52,1,52,1, + 53,1,53,1,53,1,53,1,53,1,53,5,53,701,8,53,10,53,12,53,704,9,53,1, + 53,1,53,1,53,1,53,1,53,5,53,711,8,53,10,53,12,53,714,9,53,1,53,1, + 53,1,54,1,54,3,54,720,8,54,1,55,1,55,1,55,1,55,1,55,1,56,1,56,1, + 56,5,56,730,8,56,10,56,12,56,733,9,56,1,57,1,57,1,57,5,57,738,8, + 57,10,57,12,57,741,9,57,1,58,3,58,744,8,58,1,58,1,58,1,59,1,59,1, + 59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1, + 59,1,59,1,59,1,59,1,59,1,59,3,59,769,8,59,1,60,1,60,1,61,1,61,1, + 62,1,62,1,62,1,62,1,62,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,64,1, + 64,1,64,1,64,1,64,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1,65,1, + 65,3,65,802,8,65,1,66,1,66,1,66,1,66,1,66,1,66,3,66,810,8,66,1,67, + 1,67,1,67,5,67,815,8,67,10,67,12,67,818,9,67,3,67,820,8,67,1,68, + 1,68,1,68,3,68,825,8,68,1,68,1,68,1,69,1,69,1,69,1,69,1,70,1,70, + 1,71,1,71,1,71,1,71,1,71,1,71,1,71,1,71,3,71,843,8,71,1,72,1,72, + 3,72,847,8,72,1,73,1,73,3,73,851,8,73,1,74,1,74,1,75,1,75,3,75,857, + 8,75,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76, + 1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,1,76,3,76,882, + 8,76,1,77,1,77,1,78,1,78,1,79,1,79,1,79,1,79,1,79,1,79,1,79,1,80, + 1,80,1,81,1,81,1,81,1,81,1,81,1,81,1,81,1,82,1,82,1,83,1,83,1,84, + 1,84,3,84,910,8,84,1,85,1,85,1,85,1,85,1,85,1,85,1,85,1,85,1,85, + 1,86,1,86,1,87,1,87,1,88,1,88,1,89,1,89,1,90,1,90,1,91,1,91,1,92, + 1,92,1,93,1,93,1,94,1,94,1,94,1,94,1,94,1,94,3,94,943,8,94,1,95, + 1,95,1,95,1,95,1,96,1,96,1,97,3,97,952,8,97,1,97,1,97,1,98,3,98, + 957,8,98,1,98,1,98,1,99,1,99,1,100,1,100,1,100,3,100,966,8,100,1, + 101,1,101,1,101,1,102,1,102,1,102,1,103,1,103,1,103,1,104,1,104, + 1,105,1,105,1,106,1,106,1,106,1,106,5,106,985,8,106,10,106,12,106, + 988,9,106,1,106,1,106,1,107,1,107,1,107,5,107,995,8,107,10,107,12, + 107,998,9,107,1,108,1,108,1,108,5,108,1003,8,108,10,108,12,108,1006, + 9,108,1,109,1,109,1,109,5,109,1011,8,109,10,109,12,109,1014,9,109, + 1,110,3,110,1017,8,110,1,110,1,110,1,110,1,110,1,110,1,110,1,110, + 3,110,1026,8,110,1,111,3,111,1029,8,111,1,111,1,111,1,112,1,112, + 1,112,5,112,1036,8,112,10,112,12,112,1039,9,112,1,112,3,112,1042, + 8,112,1,112,1,112,1,112,1,112,1,112,1,112,1,112,1,112,1,112,1,112, + 1,112,1,112,3,112,1056,8,112,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113,1,113, + 1,113,1,113,1,113,1,113,1,113,1,113,3,113,1158,8,113,1,113,0,2,90, + 94,114,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40, + 42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84, + 86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,118,120, + 122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152, + 154,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184, + 186,188,190,192,194,196,198,200,202,204,206,208,210,212,214,216, + 218,220,222,224,226,0,21,1,0,118,119,1,0,18,19,2,0,137,137,171,171, + 5,0,135,136,140,140,143,143,148,148,150,153,1,0,120,122,3,0,7,7, + 56,56,289,319,1,0,195,204,13,0,68,70,74,74,76,76,79,79,82,82,84, + 84,86,87,89,92,94,97,205,222,224,225,227,243,246,255,4,0,69,69,212, + 212,241,241,243,243,8,0,70,70,76,76,82,82,84,84,89,89,91,92,95,95, + 97,97,8,0,71,73,75,75,77,78,80,80,85,85,88,88,93,93,98,98,1,0,244, + 245,1,0,275,280,2,0,256,260,262,273,2,0,67,67,112,117,1,0,282,285, + 1,0,286,288,1,0,333,334,1,0,65,66,9,0,70,73,75,78,80,80,82,82,84, + 85,88,89,91,93,95,95,97,98,9,0,31,31,70,70,76,76,83,84,89,89,91, + 92,95,95,97,97,321,327,1318,0,229,1,0,0,0,2,233,1,0,0,0,4,235,1, + 0,0,0,6,237,1,0,0,0,8,248,1,0,0,0,10,266,1,0,0,0,12,284,1,0,0,0, + 14,286,1,0,0,0,16,289,1,0,0,0,18,292,1,0,0,0,20,295,1,0,0,0,22,301, + 1,0,0,0,24,310,1,0,0,0,26,342,1,0,0,0,28,357,1,0,0,0,30,360,1,0, + 0,0,32,369,1,0,0,0,34,377,1,0,0,0,36,385,1,0,0,0,38,390,1,0,0,0, + 40,394,1,0,0,0,42,398,1,0,0,0,44,413,1,0,0,0,46,415,1,0,0,0,48,417, + 1,0,0,0,50,433,1,0,0,0,52,435,1,0,0,0,54,478,1,0,0,0,56,480,1,0, + 0,0,58,487,1,0,0,0,60,503,1,0,0,0,62,505,1,0,0,0,64,513,1,0,0,0, + 66,517,1,0,0,0,68,529,1,0,0,0,70,531,1,0,0,0,72,536,1,0,0,0,74,546, + 1,0,0,0,76,554,1,0,0,0,78,558,1,0,0,0,80,578,1,0,0,0,82,580,1,0, + 0,0,84,582,1,0,0,0,86,591,1,0,0,0,88,602,1,0,0,0,90,610,1,0,0,0, + 92,636,1,0,0,0,94,648,1,0,0,0,96,665,1,0,0,0,98,667,1,0,0,0,100, + 674,1,0,0,0,102,678,1,0,0,0,104,680,1,0,0,0,106,694,1,0,0,0,108, + 719,1,0,0,0,110,721,1,0,0,0,112,726,1,0,0,0,114,734,1,0,0,0,116, + 743,1,0,0,0,118,768,1,0,0,0,120,770,1,0,0,0,122,772,1,0,0,0,124, + 774,1,0,0,0,126,779,1,0,0,0,128,786,1,0,0,0,130,801,1,0,0,0,132, + 809,1,0,0,0,134,819,1,0,0,0,136,824,1,0,0,0,138,828,1,0,0,0,140, + 832,1,0,0,0,142,842,1,0,0,0,144,846,1,0,0,0,146,850,1,0,0,0,148, + 852,1,0,0,0,150,856,1,0,0,0,152,881,1,0,0,0,154,883,1,0,0,0,156, + 885,1,0,0,0,158,887,1,0,0,0,160,894,1,0,0,0,162,896,1,0,0,0,164, + 903,1,0,0,0,166,905,1,0,0,0,168,909,1,0,0,0,170,911,1,0,0,0,172, + 920,1,0,0,0,174,922,1,0,0,0,176,924,1,0,0,0,178,926,1,0,0,0,180, + 928,1,0,0,0,182,930,1,0,0,0,184,932,1,0,0,0,186,934,1,0,0,0,188, + 942,1,0,0,0,190,944,1,0,0,0,192,948,1,0,0,0,194,951,1,0,0,0,196, + 956,1,0,0,0,198,960,1,0,0,0,200,965,1,0,0,0,202,967,1,0,0,0,204, + 970,1,0,0,0,206,973,1,0,0,0,208,976,1,0,0,0,210,978,1,0,0,0,212, + 980,1,0,0,0,214,991,1,0,0,0,216,999,1,0,0,0,218,1007,1,0,0,0,220, + 1025,1,0,0,0,222,1028,1,0,0,0,224,1055,1,0,0,0,226,1157,1,0,0,0, + 228,230,3,2,1,0,229,228,1,0,0,0,229,230,1,0,0,0,230,231,1,0,0,0, + 231,232,5,0,0,1,232,1,1,0,0,0,233,234,3,4,2,0,234,3,1,0,0,0,235, + 236,3,6,3,0,236,5,1,0,0,0,237,242,3,8,4,0,238,239,5,109,0,0,239, + 241,3,10,5,0,240,238,1,0,0,0,241,244,1,0,0,0,242,240,1,0,0,0,242, + 243,1,0,0,0,243,7,1,0,0,0,244,242,1,0,0,0,245,249,3,12,6,0,246,249, + 3,14,7,0,247,249,3,16,8,0,248,245,1,0,0,0,248,246,1,0,0,0,248,247, + 1,0,0,0,249,9,1,0,0,0,250,267,3,18,9,0,251,267,3,20,10,0,252,267, + 3,22,11,0,253,267,3,24,12,0,254,267,3,26,13,0,255,267,3,28,14,0, + 256,267,3,30,15,0,257,267,3,32,16,0,258,267,3,34,17,0,259,267,3, + 36,18,0,260,267,3,38,19,0,261,267,3,40,20,0,262,267,3,42,21,0,263, + 267,3,48,24,0,264,267,3,52,26,0,265,267,3,56,28,0,266,250,1,0,0, + 0,266,251,1,0,0,0,266,252,1,0,0,0,266,253,1,0,0,0,266,254,1,0,0, + 0,266,255,1,0,0,0,266,256,1,0,0,0,266,257,1,0,0,0,266,258,1,0,0, + 0,266,259,1,0,0,0,266,260,1,0,0,0,266,261,1,0,0,0,266,262,1,0,0, + 0,266,263,1,0,0,0,266,264,1,0,0,0,266,265,1,0,0,0,267,11,1,0,0,0, + 268,270,5,2,0,0,269,268,1,0,0,0,269,270,1,0,0,0,270,271,1,0,0,0, + 271,285,3,60,30,0,272,274,5,2,0,0,273,272,1,0,0,0,273,274,1,0,0, + 0,274,275,1,0,0,0,275,276,3,60,30,0,276,277,3,90,45,0,277,285,1, + 0,0,0,278,280,5,2,0,0,279,278,1,0,0,0,279,280,1,0,0,0,280,281,1, + 0,0,0,281,282,3,90,45,0,282,283,3,60,30,0,283,285,1,0,0,0,284,269, + 1,0,0,0,284,273,1,0,0,0,284,279,1,0,0,0,285,13,1,0,0,0,286,287,5, + 3,0,0,287,288,3,62,31,0,288,15,1,0,0,0,289,290,5,4,0,0,290,291,5, + 33,0,0,291,17,1,0,0,0,292,293,5,6,0,0,293,294,3,90,45,0,294,19,1, + 0,0,0,295,297,5,7,0,0,296,298,7,0,0,0,297,296,1,0,0,0,297,298,1, + 0,0,0,298,299,1,0,0,0,299,300,3,112,56,0,300,21,1,0,0,0,301,302, + 5,8,0,0,302,307,3,64,32,0,303,304,5,110,0,0,304,306,3,64,32,0,305, + 303,1,0,0,0,306,309,1,0,0,0,307,305,1,0,0,0,307,308,1,0,0,0,308, + 23,1,0,0,0,309,307,1,0,0,0,310,314,5,9,0,0,311,312,5,42,0,0,312, + 313,5,112,0,0,313,315,3,194,97,0,314,311,1,0,0,0,314,315,1,0,0,0, + 315,319,1,0,0,0,316,317,5,43,0,0,317,318,5,112,0,0,318,320,3,198, + 99,0,319,316,1,0,0,0,319,320,1,0,0,0,320,324,1,0,0,0,321,322,5,44, + 0,0,322,323,5,112,0,0,323,325,3,192,96,0,324,321,1,0,0,0,324,325, + 1,0,0,0,325,326,1,0,0,0,326,331,3,78,39,0,327,328,5,110,0,0,328, + 330,3,78,39,0,329,327,1,0,0,0,330,333,1,0,0,0,331,329,1,0,0,0,331, + 332,1,0,0,0,332,335,1,0,0,0,333,331,1,0,0,0,334,336,3,68,34,0,335, + 334,1,0,0,0,335,336,1,0,0,0,336,340,1,0,0,0,337,338,5,41,0,0,338, + 339,5,112,0,0,339,341,3,198,99,0,340,337,1,0,0,0,340,341,1,0,0,0, + 341,25,1,0,0,0,342,344,5,10,0,0,343,345,3,194,97,0,344,343,1,0,0, + 0,344,345,1,0,0,0,345,346,1,0,0,0,346,350,3,112,56,0,347,348,5,39, + 0,0,348,349,5,112,0,0,349,351,3,198,99,0,350,347,1,0,0,0,350,351, + 1,0,0,0,351,355,1,0,0,0,352,353,5,40,0,0,353,354,5,112,0,0,354,356, + 3,198,99,0,355,352,1,0,0,0,355,356,1,0,0,0,356,27,1,0,0,0,357,358, + 5,11,0,0,358,359,3,74,37,0,359,29,1,0,0,0,360,361,5,12,0,0,361,366, + 3,76,38,0,362,363,5,110,0,0,363,365,3,76,38,0,364,362,1,0,0,0,365, + 368,1,0,0,0,366,364,1,0,0,0,366,367,1,0,0,0,367,31,1,0,0,0,368,366, + 1,0,0,0,369,371,5,13,0,0,370,372,3,194,97,0,371,370,1,0,0,0,371, + 372,1,0,0,0,372,375,1,0,0,0,373,374,5,5,0,0,374,376,3,194,97,0,375, + 373,1,0,0,0,375,376,1,0,0,0,376,33,1,0,0,0,377,379,5,14,0,0,378, + 380,3,194,97,0,379,378,1,0,0,0,379,380,1,0,0,0,380,381,1,0,0,0,381, + 383,3,112,56,0,382,384,3,66,33,0,383,382,1,0,0,0,383,384,1,0,0,0, + 384,35,1,0,0,0,385,386,5,15,0,0,386,388,3,112,56,0,387,389,3,66, + 33,0,388,387,1,0,0,0,388,389,1,0,0,0,389,37,1,0,0,0,390,391,5,20, + 0,0,391,392,3,88,44,0,392,393,3,192,96,0,393,39,1,0,0,0,394,395, + 5,16,0,0,395,396,3,88,44,0,396,397,3,192,96,0,397,41,1,0,0,0,398, + 402,5,22,0,0,399,401,3,44,22,0,400,399,1,0,0,0,401,404,1,0,0,0,402, + 400,1,0,0,0,402,403,1,0,0,0,403,405,1,0,0,0,404,402,1,0,0,0,405, + 406,3,88,44,0,406,43,1,0,0,0,407,408,5,23,0,0,408,409,5,112,0,0, + 409,414,3,192,96,0,410,411,5,21,0,0,411,412,5,112,0,0,412,414,3, + 192,96,0,413,407,1,0,0,0,413,410,1,0,0,0,414,45,1,0,0,0,415,416, + 7,1,0,0,416,47,1,0,0,0,417,421,5,24,0,0,418,420,3,50,25,0,419,418, + 1,0,0,0,420,423,1,0,0,0,421,419,1,0,0,0,421,422,1,0,0,0,422,49,1, + 0,0,0,423,421,1,0,0,0,424,425,5,45,0,0,425,426,5,112,0,0,426,434, + 3,194,97,0,427,428,5,46,0,0,428,429,5,112,0,0,429,434,3,194,97,0, + 430,431,5,47,0,0,431,432,5,112,0,0,432,434,3,192,96,0,433,424,1, + 0,0,0,433,427,1,0,0,0,433,430,1,0,0,0,434,51,1,0,0,0,435,439,5,25, + 0,0,436,438,3,54,27,0,437,436,1,0,0,0,438,441,1,0,0,0,439,437,1, + 0,0,0,439,440,1,0,0,0,440,53,1,0,0,0,441,439,1,0,0,0,442,443,5,48, + 0,0,443,444,5,112,0,0,444,479,3,194,97,0,445,446,5,49,0,0,446,447, + 5,112,0,0,447,479,3,194,97,0,448,449,5,50,0,0,449,450,5,112,0,0, + 450,479,3,194,97,0,451,452,5,51,0,0,452,453,5,112,0,0,453,479,3, + 194,97,0,454,455,5,52,0,0,455,456,5,112,0,0,456,479,3,196,98,0,457, + 458,5,53,0,0,458,459,5,112,0,0,459,479,3,196,98,0,460,461,5,54,0, + 0,461,462,5,112,0,0,462,479,3,192,96,0,463,464,5,55,0,0,464,465, + 5,112,0,0,465,479,3,192,96,0,466,467,5,215,0,0,467,468,5,112,0,0, + 468,479,3,192,96,0,469,470,5,56,0,0,470,471,5,112,0,0,471,479,3, + 192,96,0,472,473,5,57,0,0,473,474,5,112,0,0,474,479,3,194,97,0,475, + 476,5,58,0,0,476,477,5,112,0,0,477,479,3,196,98,0,478,442,1,0,0, + 0,478,445,1,0,0,0,478,448,1,0,0,0,478,451,1,0,0,0,478,454,1,0,0, + 0,478,457,1,0,0,0,478,460,1,0,0,0,478,463,1,0,0,0,478,466,1,0,0, + 0,478,469,1,0,0,0,478,472,1,0,0,0,478,475,1,0,0,0,479,55,1,0,0,0, + 480,484,5,26,0,0,481,483,3,58,29,0,482,481,1,0,0,0,483,486,1,0,0, + 0,484,482,1,0,0,0,484,485,1,0,0,0,485,57,1,0,0,0,486,484,1,0,0,0, + 487,488,3,220,110,0,488,489,5,112,0,0,489,490,3,188,94,0,490,59, + 1,0,0,0,491,492,5,29,0,0,492,493,5,112,0,0,493,504,3,62,31,0,494, + 495,5,30,0,0,495,496,5,112,0,0,496,504,3,62,31,0,497,498,5,29,0, + 0,498,499,5,112,0,0,499,504,3,110,55,0,500,501,5,30,0,0,501,502, + 5,112,0,0,502,504,3,110,55,0,503,491,1,0,0,0,503,494,1,0,0,0,503, + 497,1,0,0,0,503,500,1,0,0,0,504,61,1,0,0,0,505,510,3,108,54,0,506, + 507,5,110,0,0,507,509,3,108,54,0,508,506,1,0,0,0,509,512,1,0,0,0, + 510,508,1,0,0,0,510,511,1,0,0,0,511,63,1,0,0,0,512,510,1,0,0,0,513, + 514,3,122,61,0,514,515,5,27,0,0,515,516,3,122,61,0,516,65,1,0,0, + 0,517,518,5,28,0,0,518,519,3,112,56,0,519,67,1,0,0,0,520,521,5,28, + 0,0,521,530,3,112,56,0,522,523,5,28,0,0,523,530,3,70,35,0,524,525, + 5,28,0,0,525,526,3,70,35,0,526,527,5,110,0,0,527,528,3,112,56,0, + 528,530,1,0,0,0,529,520,1,0,0,0,529,522,1,0,0,0,529,524,1,0,0,0, + 530,69,1,0,0,0,531,534,3,72,36,0,532,533,5,27,0,0,533,535,3,214, + 107,0,534,532,1,0,0,0,534,535,1,0,0,0,535,71,1,0,0,0,536,537,5,320, + 0,0,537,538,5,125,0,0,538,539,3,120,60,0,539,540,5,110,0,0,540,542, + 3,188,94,0,541,543,3,210,105,0,542,541,1,0,0,0,542,543,1,0,0,0,543, + 544,1,0,0,0,544,545,5,126,0,0,545,73,1,0,0,0,546,551,3,116,58,0, + 547,548,5,110,0,0,548,550,3,116,58,0,549,547,1,0,0,0,550,553,1,0, + 0,0,551,549,1,0,0,0,551,552,1,0,0,0,552,75,1,0,0,0,553,551,1,0,0, + 0,554,555,3,120,60,0,555,556,5,112,0,0,556,557,3,88,44,0,557,77, + 1,0,0,0,558,561,3,80,40,0,559,560,5,27,0,0,560,562,3,122,61,0,561, + 559,1,0,0,0,561,562,1,0,0,0,562,79,1,0,0,0,563,564,3,82,41,0,564, + 565,5,125,0,0,565,566,3,94,47,0,566,567,5,126,0,0,567,579,1,0,0, + 0,568,569,5,136,0,0,569,570,5,125,0,0,570,579,5,126,0,0,571,572, + 7,2,0,0,572,573,5,125,0,0,573,574,3,94,47,0,574,575,5,126,0,0,575, + 579,1,0,0,0,576,579,3,86,43,0,577,579,3,84,42,0,578,563,1,0,0,0, + 578,568,1,0,0,0,578,571,1,0,0,0,578,576,1,0,0,0,578,577,1,0,0,0, + 579,81,1,0,0,0,580,581,7,3,0,0,581,83,1,0,0,0,582,583,5,155,0,0, + 583,584,5,125,0,0,584,587,3,120,60,0,585,586,5,110,0,0,586,588,3, + 194,97,0,587,585,1,0,0,0,587,588,1,0,0,0,588,589,1,0,0,0,589,590, + 5,126,0,0,590,85,1,0,0,0,591,592,5,154,0,0,592,593,5,114,0,0,593, + 594,3,194,97,0,594,595,5,113,0,0,595,596,5,125,0,0,596,597,3,120, + 60,0,597,598,5,126,0,0,598,87,1,0,0,0,599,603,3,90,45,0,600,603, + 3,92,46,0,601,603,3,94,47,0,602,599,1,0,0,0,602,600,1,0,0,0,602, + 601,1,0,0,0,603,89,1,0,0,0,604,605,6,45,-1,0,605,611,3,92,46,0,606, + 607,5,61,0,0,607,611,3,90,45,6,608,611,3,100,50,0,609,611,3,102, + 51,0,610,604,1,0,0,0,610,606,1,0,0,0,610,608,1,0,0,0,610,609,1,0, + 0,0,611,625,1,0,0,0,612,613,10,5,0,0,613,614,5,62,0,0,614,624,3, + 90,45,6,615,617,10,4,0,0,616,618,5,63,0,0,617,616,1,0,0,0,617,618, + 1,0,0,0,618,619,1,0,0,0,619,624,3,90,45,5,620,621,10,3,0,0,621,622, + 5,64,0,0,622,624,3,90,45,4,623,612,1,0,0,0,623,615,1,0,0,0,623,620, + 1,0,0,0,624,627,1,0,0,0,625,623,1,0,0,0,625,626,1,0,0,0,626,91,1, + 0,0,0,627,625,1,0,0,0,628,629,3,94,47,0,629,630,3,182,91,0,630,631, + 3,94,47,0,631,637,1,0,0,0,632,633,3,94,47,0,633,634,5,60,0,0,634, + 635,3,212,106,0,635,637,1,0,0,0,636,628,1,0,0,0,636,632,1,0,0,0, + 637,93,1,0,0,0,638,639,6,47,-1,0,639,649,3,96,48,0,640,649,3,98, + 49,0,641,649,3,162,81,0,642,649,3,158,79,0,643,649,3,170,85,0,644, + 645,5,125,0,0,645,646,3,94,47,0,646,647,5,126,0,0,647,649,1,0,0, + 0,648,638,1,0,0,0,648,640,1,0,0,0,648,641,1,0,0,0,648,642,1,0,0, + 0,648,643,1,0,0,0,648,644,1,0,0,0,649,658,1,0,0,0,650,651,10,8,0, + 0,651,652,7,4,0,0,652,657,3,94,47,9,653,654,10,7,0,0,654,655,7,0, + 0,0,655,657,3,94,47,8,656,650,1,0,0,0,656,653,1,0,0,0,657,660,1, + 0,0,0,658,656,1,0,0,0,658,659,1,0,0,0,659,95,1,0,0,0,660,658,1,0, + 0,0,661,666,3,124,62,0,662,666,3,126,63,0,663,666,3,120,60,0,664, + 666,3,188,94,0,665,661,1,0,0,0,665,662,1,0,0,0,665,663,1,0,0,0,665, + 664,1,0,0,0,666,97,1,0,0,0,667,668,3,180,90,0,668,669,5,125,0,0, + 669,670,3,136,68,0,670,671,5,60,0,0,671,672,3,136,68,0,672,673,5, + 126,0,0,673,99,1,0,0,0,674,675,3,128,64,0,675,101,1,0,0,0,676,679, + 3,104,52,0,677,679,3,106,53,0,678,676,1,0,0,0,678,677,1,0,0,0,679, + 103,1,0,0,0,680,681,3,184,92,0,681,682,5,125,0,0,682,683,3,146,73, + 0,683,684,5,110,0,0,684,689,3,148,74,0,685,686,5,110,0,0,686,688, + 3,138,69,0,687,685,1,0,0,0,688,691,1,0,0,0,689,687,1,0,0,0,689,690, + 1,0,0,0,690,692,1,0,0,0,691,689,1,0,0,0,692,693,5,126,0,0,693,105, + 1,0,0,0,694,695,3,186,93,0,695,696,5,125,0,0,696,697,5,127,0,0,697, + 702,3,142,71,0,698,699,5,110,0,0,699,701,3,142,71,0,700,698,1,0, + 0,0,701,704,1,0,0,0,702,700,1,0,0,0,702,703,1,0,0,0,703,705,1,0, + 0,0,704,702,1,0,0,0,705,706,5,128,0,0,706,707,5,110,0,0,707,712, + 3,148,74,0,708,709,5,110,0,0,709,711,3,138,69,0,710,708,1,0,0,0, + 711,714,1,0,0,0,712,710,1,0,0,0,712,713,1,0,0,0,713,715,1,0,0,0, + 714,712,1,0,0,0,715,716,5,126,0,0,716,107,1,0,0,0,717,720,3,216, + 108,0,718,720,5,332,0,0,719,717,1,0,0,0,719,718,1,0,0,0,720,109, + 1,0,0,0,721,722,3,214,107,0,722,723,5,125,0,0,723,724,3,134,67,0, + 724,725,5,126,0,0,725,111,1,0,0,0,726,731,3,120,60,0,727,728,5,110, + 0,0,728,730,3,120,60,0,729,727,1,0,0,0,730,733,1,0,0,0,731,729,1, + 0,0,0,731,732,1,0,0,0,732,113,1,0,0,0,733,731,1,0,0,0,734,739,3, + 122,61,0,735,736,5,110,0,0,736,738,3,122,61,0,737,735,1,0,0,0,738, + 741,1,0,0,0,739,737,1,0,0,0,739,740,1,0,0,0,740,115,1,0,0,0,741, + 739,1,0,0,0,742,744,7,0,0,0,743,742,1,0,0,0,743,744,1,0,0,0,744, + 745,1,0,0,0,745,746,3,118,59,0,746,117,1,0,0,0,747,769,3,120,60, + 0,748,749,5,35,0,0,749,750,5,125,0,0,750,751,3,120,60,0,751,752, + 5,126,0,0,752,769,1,0,0,0,753,754,5,36,0,0,754,755,5,125,0,0,755, + 756,3,120,60,0,756,757,5,126,0,0,757,769,1,0,0,0,758,759,5,37,0, + 0,759,760,5,125,0,0,760,761,3,120,60,0,761,762,5,126,0,0,762,769, + 1,0,0,0,763,764,5,38,0,0,764,765,5,125,0,0,765,766,3,120,60,0,766, + 767,5,126,0,0,767,769,1,0,0,0,768,747,1,0,0,0,768,748,1,0,0,0,768, + 753,1,0,0,0,768,758,1,0,0,0,768,763,1,0,0,0,769,119,1,0,0,0,770, + 771,3,214,107,0,771,121,1,0,0,0,772,773,3,218,109,0,773,123,1,0, + 0,0,774,775,3,132,66,0,775,776,5,125,0,0,776,777,3,134,67,0,777, + 778,5,126,0,0,778,125,1,0,0,0,779,780,5,274,0,0,780,781,5,125,0, + 0,781,782,3,88,44,0,782,783,5,27,0,0,783,784,3,130,65,0,784,785, + 5,126,0,0,785,127,1,0,0,0,786,787,3,174,87,0,787,788,5,125,0,0,788, + 789,3,134,67,0,789,790,5,126,0,0,790,129,1,0,0,0,791,802,5,212,0, + 0,792,802,5,241,0,0,793,802,5,243,0,0,794,802,5,102,0,0,795,802, + 5,103,0,0,796,802,5,104,0,0,797,802,5,105,0,0,798,802,5,106,0,0, + 799,802,5,107,0,0,800,802,5,108,0,0,801,791,1,0,0,0,801,792,1,0, + 0,0,801,793,1,0,0,0,801,794,1,0,0,0,801,795,1,0,0,0,801,796,1,0, + 0,0,801,797,1,0,0,0,801,798,1,0,0,0,801,799,1,0,0,0,801,800,1,0, + 0,0,802,131,1,0,0,0,803,810,3,152,76,0,804,810,3,156,78,0,805,810, + 3,178,89,0,806,810,3,174,87,0,807,810,3,176,88,0,808,810,3,180,90, + 0,809,803,1,0,0,0,809,804,1,0,0,0,809,805,1,0,0,0,809,806,1,0,0, + 0,809,807,1,0,0,0,809,808,1,0,0,0,810,133,1,0,0,0,811,816,3,136, + 68,0,812,813,5,110,0,0,813,815,3,136,68,0,814,812,1,0,0,0,815,818, + 1,0,0,0,816,814,1,0,0,0,816,817,1,0,0,0,817,820,1,0,0,0,818,816, + 1,0,0,0,819,811,1,0,0,0,819,820,1,0,0,0,820,135,1,0,0,0,821,822, + 3,220,110,0,822,823,5,112,0,0,823,825,1,0,0,0,824,821,1,0,0,0,824, + 825,1,0,0,0,825,826,1,0,0,0,826,827,3,94,47,0,827,137,1,0,0,0,828, + 829,3,140,70,0,829,830,5,112,0,0,830,831,3,150,75,0,831,139,1,0, + 0,0,832,833,7,5,0,0,833,141,1,0,0,0,834,843,3,146,73,0,835,836,3, + 146,73,0,836,837,3,144,72,0,837,843,1,0,0,0,838,839,3,146,73,0,839, + 840,5,134,0,0,840,841,3,144,72,0,841,843,1,0,0,0,842,834,1,0,0,0, + 842,835,1,0,0,0,842,838,1,0,0,0,843,143,1,0,0,0,844,847,3,194,97, + 0,845,847,3,196,98,0,846,844,1,0,0,0,846,845,1,0,0,0,847,145,1,0, + 0,0,848,851,3,214,107,0,849,851,3,192,96,0,850,848,1,0,0,0,850,849, + 1,0,0,0,851,147,1,0,0,0,852,853,3,150,75,0,853,149,1,0,0,0,854,857, + 3,214,107,0,855,857,3,188,94,0,856,854,1,0,0,0,856,855,1,0,0,0,857, + 151,1,0,0,0,858,882,5,172,0,0,859,882,5,173,0,0,860,882,5,174,0, + 0,861,882,5,175,0,0,862,882,5,176,0,0,863,882,5,177,0,0,864,882, + 5,178,0,0,865,882,5,179,0,0,866,882,5,180,0,0,867,882,5,181,0,0, + 868,882,5,182,0,0,869,882,5,183,0,0,870,882,5,184,0,0,871,882,5, + 185,0,0,872,882,5,186,0,0,873,882,5,188,0,0,874,882,5,189,0,0,875, + 882,5,190,0,0,876,882,5,191,0,0,877,882,5,192,0,0,878,882,5,193, + 0,0,879,882,5,194,0,0,880,882,3,154,77,0,881,858,1,0,0,0,881,859, + 1,0,0,0,881,860,1,0,0,0,881,861,1,0,0,0,881,862,1,0,0,0,881,863, + 1,0,0,0,881,864,1,0,0,0,881,865,1,0,0,0,881,866,1,0,0,0,881,867, + 1,0,0,0,881,868,1,0,0,0,881,869,1,0,0,0,881,870,1,0,0,0,881,871, + 1,0,0,0,881,872,1,0,0,0,881,873,1,0,0,0,881,874,1,0,0,0,881,875, + 1,0,0,0,881,876,1,0,0,0,881,877,1,0,0,0,881,878,1,0,0,0,881,879, + 1,0,0,0,881,880,1,0,0,0,882,153,1,0,0,0,883,884,7,6,0,0,884,155, + 1,0,0,0,885,886,7,7,0,0,886,157,1,0,0,0,887,888,5,226,0,0,888,889, + 5,125,0,0,889,890,3,160,80,0,890,891,5,110,0,0,891,892,3,136,68, + 0,892,893,5,126,0,0,893,159,1,0,0,0,894,895,7,8,0,0,895,161,1,0, + 0,0,896,897,5,223,0,0,897,898,5,125,0,0,898,899,3,168,84,0,899,900, + 5,5,0,0,900,901,3,136,68,0,901,902,5,126,0,0,902,163,1,0,0,0,903, + 904,7,9,0,0,904,165,1,0,0,0,905,906,7,10,0,0,906,167,1,0,0,0,907, + 910,3,164,82,0,908,910,3,166,83,0,909,907,1,0,0,0,909,908,1,0,0, + 0,910,169,1,0,0,0,911,912,3,172,86,0,912,913,5,125,0,0,913,914,3, + 164,82,0,914,915,5,110,0,0,915,916,3,136,68,0,916,917,5,110,0,0, + 917,918,3,136,68,0,918,919,5,126,0,0,919,171,1,0,0,0,920,921,7,11, + 0,0,921,173,1,0,0,0,922,923,7,12,0,0,923,175,1,0,0,0,924,925,5,281, + 0,0,925,177,1,0,0,0,926,927,7,13,0,0,927,179,1,0,0,0,928,929,5,187, + 0,0,929,181,1,0,0,0,930,931,7,14,0,0,931,183,1,0,0,0,932,933,7,15, + 0,0,933,185,1,0,0,0,934,935,7,16,0,0,935,187,1,0,0,0,936,943,3,190, + 95,0,937,943,3,192,96,0,938,943,3,194,97,0,939,943,3,196,98,0,940, + 943,3,198,99,0,941,943,3,200,100,0,942,936,1,0,0,0,942,937,1,0,0, + 0,942,938,1,0,0,0,942,939,1,0,0,0,942,940,1,0,0,0,942,941,1,0,0, + 0,943,189,1,0,0,0,944,945,5,81,0,0,945,946,3,94,47,0,946,947,3,208, + 104,0,947,191,1,0,0,0,948,949,7,17,0,0,949,193,1,0,0,0,950,952,7, + 0,0,0,951,950,1,0,0,0,951,952,1,0,0,0,952,953,1,0,0,0,953,954,5, + 330,0,0,954,195,1,0,0,0,955,957,7,0,0,0,956,955,1,0,0,0,956,957, + 1,0,0,0,957,958,1,0,0,0,958,959,5,331,0,0,959,197,1,0,0,0,960,961, + 7,18,0,0,961,199,1,0,0,0,962,966,3,202,101,0,963,966,3,204,102,0, + 964,966,3,206,103,0,965,962,1,0,0,0,965,963,1,0,0,0,965,964,1,0, + 0,0,966,201,1,0,0,0,967,968,5,212,0,0,968,969,3,192,96,0,969,203, + 1,0,0,0,970,971,5,241,0,0,971,972,3,192,96,0,972,205,1,0,0,0,973, + 974,5,243,0,0,974,975,3,192,96,0,975,207,1,0,0,0,976,977,7,19,0, + 0,977,209,1,0,0,0,978,979,7,20,0,0,979,211,1,0,0,0,980,981,5,125, + 0,0,981,986,3,188,94,0,982,983,5,110,0,0,983,985,3,188,94,0,984, + 982,1,0,0,0,985,988,1,0,0,0,986,984,1,0,0,0,986,987,1,0,0,0,987, + 989,1,0,0,0,988,986,1,0,0,0,989,990,5,126,0,0,990,213,1,0,0,0,991, + 996,3,220,110,0,992,993,5,111,0,0,993,995,3,220,110,0,994,992,1, + 0,0,0,995,998,1,0,0,0,996,994,1,0,0,0,996,997,1,0,0,0,997,215,1, + 0,0,0,998,996,1,0,0,0,999,1004,3,222,111,0,1000,1001,5,111,0,0,1001, + 1003,3,220,110,0,1002,1000,1,0,0,0,1003,1006,1,0,0,0,1004,1002,1, + 0,0,0,1004,1005,1,0,0,0,1005,217,1,0,0,0,1006,1004,1,0,0,0,1007, + 1012,3,224,112,0,1008,1009,5,111,0,0,1009,1011,3,224,112,0,1010, + 1008,1,0,0,0,1011,1014,1,0,0,0,1012,1010,1,0,0,0,1012,1013,1,0,0, + 0,1013,219,1,0,0,0,1014,1012,1,0,0,0,1015,1017,5,111,0,0,1016,1015, + 1,0,0,0,1016,1017,1,0,0,0,1017,1018,1,0,0,0,1018,1026,5,328,0,0, + 1019,1020,5,131,0,0,1020,1021,3,220,110,0,1021,1022,5,131,0,0,1022, + 1026,1,0,0,0,1023,1026,5,335,0,0,1024,1026,3,226,113,0,1025,1016, + 1,0,0,0,1025,1019,1,0,0,0,1025,1023,1,0,0,0,1025,1024,1,0,0,0,1026, + 221,1,0,0,0,1027,1029,5,329,0,0,1028,1027,1,0,0,0,1028,1029,1,0, + 0,0,1029,1030,1,0,0,0,1030,1031,3,220,110,0,1031,223,1,0,0,0,1032, + 1037,3,220,110,0,1033,1034,5,122,0,0,1034,1036,3,220,110,0,1035, + 1033,1,0,0,0,1036,1039,1,0,0,0,1037,1035,1,0,0,0,1037,1038,1,0,0, + 0,1038,1041,1,0,0,0,1039,1037,1,0,0,0,1040,1042,5,122,0,0,1041,1040, + 1,0,0,0,1041,1042,1,0,0,0,1042,1056,1,0,0,0,1043,1044,5,129,0,0, + 1044,1045,3,224,112,0,1045,1046,5,129,0,0,1046,1056,1,0,0,0,1047, + 1048,5,130,0,0,1048,1049,3,224,112,0,1049,1050,5,130,0,0,1050,1056, + 1,0,0,0,1051,1052,5,131,0,0,1052,1053,3,224,112,0,1053,1054,5,131, + 0,0,1054,1056,1,0,0,0,1055,1032,1,0,0,0,1055,1043,1,0,0,0,1055,1047, + 1,0,0,0,1055,1051,1,0,0,0,1056,225,1,0,0,0,1057,1158,5,31,0,0,1058, + 1158,3,210,105,0,1059,1158,5,320,0,0,1060,1158,3,132,66,0,1061,1158, + 3,140,70,0,1062,1158,3,208,104,0,1063,1158,3,156,78,0,1064,1158, + 3,178,89,0,1065,1158,3,152,76,0,1066,1158,3,180,90,0,1067,1158,5, + 2,0,0,1068,1158,5,3,0,0,1069,1158,5,4,0,0,1070,1158,5,5,0,0,1071, + 1158,5,6,0,0,1072,1158,5,7,0,0,1073,1158,5,8,0,0,1074,1158,5,9,0, + 0,1075,1158,5,10,0,0,1076,1158,5,11,0,0,1077,1158,5,12,0,0,1078, + 1158,5,13,0,0,1079,1158,5,14,0,0,1080,1158,5,15,0,0,1081,1158,5, + 16,0,0,1082,1158,5,17,0,0,1083,1158,5,18,0,0,1084,1158,5,19,0,0, + 1085,1158,5,20,0,0,1086,1158,5,21,0,0,1087,1158,5,22,0,0,1088,1158, + 5,23,0,0,1089,1158,5,24,0,0,1090,1158,5,25,0,0,1091,1158,5,26,0, + 0,1092,1158,5,29,0,0,1093,1158,5,30,0,0,1094,1158,5,32,0,0,1095, + 1158,5,33,0,0,1096,1158,5,34,0,0,1097,1158,5,36,0,0,1098,1158,5, + 37,0,0,1099,1158,5,38,0,0,1100,1158,5,39,0,0,1101,1158,5,40,0,0, + 1102,1158,5,41,0,0,1103,1158,5,42,0,0,1104,1158,5,43,0,0,1105,1158, + 5,44,0,0,1106,1158,5,45,0,0,1107,1158,5,46,0,0,1108,1158,5,47,0, + 0,1109,1158,5,48,0,0,1110,1158,5,49,0,0,1111,1158,5,50,0,0,1112, + 1158,5,51,0,0,1113,1158,5,52,0,0,1114,1158,5,53,0,0,1115,1158,5, + 54,0,0,1116,1158,5,55,0,0,1117,1158,5,56,0,0,1118,1158,5,57,0,0, + 1119,1158,5,58,0,0,1120,1158,5,135,0,0,1121,1158,5,136,0,0,1122, + 1158,5,137,0,0,1123,1158,5,138,0,0,1124,1158,5,139,0,0,1125,1158, + 5,140,0,0,1126,1158,5,141,0,0,1127,1158,5,142,0,0,1128,1158,5,143, + 0,0,1129,1158,5,144,0,0,1130,1158,5,145,0,0,1131,1158,5,146,0,0, + 1132,1158,5,147,0,0,1133,1158,5,148,0,0,1134,1158,5,149,0,0,1135, + 1158,5,150,0,0,1136,1158,5,151,0,0,1137,1158,5,152,0,0,1138,1158, + 5,153,0,0,1139,1158,5,154,0,0,1140,1158,5,155,0,0,1141,1158,5,156, + 0,0,1142,1158,5,157,0,0,1143,1158,5,158,0,0,1144,1158,5,159,0,0, + 1145,1158,5,160,0,0,1146,1158,5,161,0,0,1147,1158,5,162,0,0,1148, + 1158,5,163,0,0,1149,1158,5,164,0,0,1150,1158,5,165,0,0,1151,1158, + 5,166,0,0,1152,1158,5,167,0,0,1153,1158,5,168,0,0,1154,1158,5,169, + 0,0,1155,1158,5,170,0,0,1156,1158,5,171,0,0,1157,1057,1,0,0,0,1157, + 1058,1,0,0,0,1157,1059,1,0,0,0,1157,1060,1,0,0,0,1157,1061,1,0,0, + 0,1157,1062,1,0,0,0,1157,1063,1,0,0,0,1157,1064,1,0,0,0,1157,1065, + 1,0,0,0,1157,1066,1,0,0,0,1157,1067,1,0,0,0,1157,1068,1,0,0,0,1157, + 1069,1,0,0,0,1157,1070,1,0,0,0,1157,1071,1,0,0,0,1157,1072,1,0,0, + 0,1157,1073,1,0,0,0,1157,1074,1,0,0,0,1157,1075,1,0,0,0,1157,1076, + 1,0,0,0,1157,1077,1,0,0,0,1157,1078,1,0,0,0,1157,1079,1,0,0,0,1157, + 1080,1,0,0,0,1157,1081,1,0,0,0,1157,1082,1,0,0,0,1157,1083,1,0,0, + 0,1157,1084,1,0,0,0,1157,1085,1,0,0,0,1157,1086,1,0,0,0,1157,1087, + 1,0,0,0,1157,1088,1,0,0,0,1157,1089,1,0,0,0,1157,1090,1,0,0,0,1157, + 1091,1,0,0,0,1157,1092,1,0,0,0,1157,1093,1,0,0,0,1157,1094,1,0,0, + 0,1157,1095,1,0,0,0,1157,1096,1,0,0,0,1157,1097,1,0,0,0,1157,1098, + 1,0,0,0,1157,1099,1,0,0,0,1157,1100,1,0,0,0,1157,1101,1,0,0,0,1157, + 1102,1,0,0,0,1157,1103,1,0,0,0,1157,1104,1,0,0,0,1157,1105,1,0,0, + 0,1157,1106,1,0,0,0,1157,1107,1,0,0,0,1157,1108,1,0,0,0,1157,1109, + 1,0,0,0,1157,1110,1,0,0,0,1157,1111,1,0,0,0,1157,1112,1,0,0,0,1157, + 1113,1,0,0,0,1157,1114,1,0,0,0,1157,1115,1,0,0,0,1157,1116,1,0,0, + 0,1157,1117,1,0,0,0,1157,1118,1,0,0,0,1157,1119,1,0,0,0,1157,1120, + 1,0,0,0,1157,1121,1,0,0,0,1157,1122,1,0,0,0,1157,1123,1,0,0,0,1157, + 1124,1,0,0,0,1157,1125,1,0,0,0,1157,1126,1,0,0,0,1157,1127,1,0,0, + 0,1157,1128,1,0,0,0,1157,1129,1,0,0,0,1157,1130,1,0,0,0,1157,1131, + 1,0,0,0,1157,1132,1,0,0,0,1157,1133,1,0,0,0,1157,1134,1,0,0,0,1157, + 1135,1,0,0,0,1157,1136,1,0,0,0,1157,1137,1,0,0,0,1157,1138,1,0,0, + 0,1157,1139,1,0,0,0,1157,1140,1,0,0,0,1157,1141,1,0,0,0,1157,1142, + 1,0,0,0,1157,1143,1,0,0,0,1157,1144,1,0,0,0,1157,1145,1,0,0,0,1157, + 1146,1,0,0,0,1157,1147,1,0,0,0,1157,1148,1,0,0,0,1157,1149,1,0,0, + 0,1157,1150,1,0,0,0,1157,1151,1,0,0,0,1157,1152,1,0,0,0,1157,1153, + 1,0,0,0,1157,1154,1,0,0,0,1157,1155,1,0,0,0,1157,1156,1,0,0,0,1158, + 227,1,0,0,0,86,229,242,248,266,269,273,279,284,297,307,314,319,324, + 331,335,340,344,350,355,366,371,375,379,383,388,402,413,421,433, + 439,478,484,503,510,529,534,542,551,561,578,587,602,610,617,623, + 625,636,648,656,658,665,678,689,702,712,719,731,739,743,768,801, + 809,816,819,824,842,846,850,856,881,909,942,951,956,965,986,996, + 1004,1012,1016,1025,1028,1037,1041,1055,1157 + ]; + + private static __ATN: antlr.ATN; + public static get _ATN(): antlr.ATN { + if (!OpenSearchPPLParser.__ATN) { + OpenSearchPPLParser.__ATN = new antlr.ATNDeserializer().deserialize(OpenSearchPPLParser._serializedATN); + } + + return OpenSearchPPLParser.__ATN; + } + + + private static readonly vocabulary = new antlr.Vocabulary(OpenSearchPPLParser.literalNames, OpenSearchPPLParser.symbolicNames, []); + + public override get vocabulary(): antlr.Vocabulary { + return OpenSearchPPLParser.vocabulary; + } + + private static readonly decisionsToDFA = OpenSearchPPLParser._ATN.decisionToState.map( (ds: antlr.DecisionState, index: number) => new antlr.DFA(ds, index) ); +} + +export class RootContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public EOF(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.EOF, 0)!; + } + public pplStatement(): PplStatementContext | null { + return this.getRuleContext(0, PplStatementContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_root; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRoot) { + return visitor.visitRoot(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PplStatementContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public dmlStatement(): DmlStatementContext { + return this.getRuleContext(0, DmlStatementContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_pplStatement; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPplStatement) { + return visitor.visitPplStatement(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DmlStatementContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public queryStatement(): QueryStatementContext { + return this.getRuleContext(0, QueryStatementContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_dmlStatement; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDmlStatement) { + return visitor.visitDmlStatement(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class QueryStatementContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public pplCommands(): PplCommandsContext { + return this.getRuleContext(0, PplCommandsContext)!; + } + public PIPE(): antlr.TerminalNode[]; + public PIPE(i: number): antlr.TerminalNode | null; + public PIPE(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.PIPE); + } else { + return this.getToken(OpenSearchPPLParser.PIPE, i); + } + } + public commands(): CommandsContext[]; + public commands(i: number): CommandsContext | null; + public commands(i?: number): CommandsContext[] | CommandsContext | null { + if (i === undefined) { + return this.getRuleContexts(CommandsContext); + } + + return this.getRuleContext(i, CommandsContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_queryStatement; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitQueryStatement) { + return visitor.visitQueryStatement(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PplCommandsContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public searchCommand(): SearchCommandContext | null { + return this.getRuleContext(0, SearchCommandContext); + } + public describeCommand(): DescribeCommandContext | null { + return this.getRuleContext(0, DescribeCommandContext); + } + public showDataSourcesCommand(): ShowDataSourcesCommandContext | null { + return this.getRuleContext(0, ShowDataSourcesCommandContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_pplCommands; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPplCommands) { + return visitor.visitPplCommands(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class CommandsContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public whereCommand(): WhereCommandContext | null { + return this.getRuleContext(0, WhereCommandContext); + } + public fieldsCommand(): FieldsCommandContext | null { + return this.getRuleContext(0, FieldsCommandContext); + } + public renameCommand(): RenameCommandContext | null { + return this.getRuleContext(0, RenameCommandContext); + } + public statsCommand(): StatsCommandContext | null { + return this.getRuleContext(0, StatsCommandContext); + } + public dedupCommand(): DedupCommandContext | null { + return this.getRuleContext(0, DedupCommandContext); + } + public sortCommand(): SortCommandContext | null { + return this.getRuleContext(0, SortCommandContext); + } + public evalCommand(): EvalCommandContext | null { + return this.getRuleContext(0, EvalCommandContext); + } + public headCommand(): HeadCommandContext | null { + return this.getRuleContext(0, HeadCommandContext); + } + public topCommand(): TopCommandContext | null { + return this.getRuleContext(0, TopCommandContext); + } + public rareCommand(): RareCommandContext | null { + return this.getRuleContext(0, RareCommandContext); + } + public grokCommand(): GrokCommandContext | null { + return this.getRuleContext(0, GrokCommandContext); + } + public parseCommand(): ParseCommandContext | null { + return this.getRuleContext(0, ParseCommandContext); + } + public patternsCommand(): PatternsCommandContext | null { + return this.getRuleContext(0, PatternsCommandContext); + } + public kmeansCommand(): KmeansCommandContext | null { + return this.getRuleContext(0, KmeansCommandContext); + } + public adCommand(): AdCommandContext | null { + return this.getRuleContext(0, AdCommandContext); + } + public mlCommand(): MlCommandContext | null { + return this.getRuleContext(0, MlCommandContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_commands; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitCommands) { + return visitor.visitCommands(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SearchCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_searchCommand; + } + public override copyFrom(ctx: SearchCommandContext): void { + super.copyFrom(ctx); + } +} +export class SearchFromFilterContext extends SearchCommandContext { + public constructor(ctx: SearchCommandContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public fromClause(): FromClauseContext { + return this.getRuleContext(0, FromClauseContext)!; + } + public logicalExpression(): LogicalExpressionContext { + return this.getRuleContext(0, LogicalExpressionContext)!; + } + public SEARCH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SEARCH, 0); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSearchFromFilter) { + return visitor.visitSearchFromFilter(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class SearchFromContext extends SearchCommandContext { + public constructor(ctx: SearchCommandContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public fromClause(): FromClauseContext { + return this.getRuleContext(0, FromClauseContext)!; + } + public SEARCH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SEARCH, 0); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSearchFrom) { + return visitor.visitSearchFrom(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class SearchFilterFromContext extends SearchCommandContext { + public constructor(ctx: SearchCommandContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public logicalExpression(): LogicalExpressionContext { + return this.getRuleContext(0, LogicalExpressionContext)!; + } + public fromClause(): FromClauseContext { + return this.getRuleContext(0, FromClauseContext)!; + } + public SEARCH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SEARCH, 0); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSearchFilterFrom) { + return visitor.visitSearchFilterFrom(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DescribeCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public DESCRIBE(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.DESCRIBE, 0)!; + } + public tableSourceClause(): TableSourceClauseContext { + return this.getRuleContext(0, TableSourceClauseContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_describeCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDescribeCommand) { + return visitor.visitDescribeCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ShowDataSourcesCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public SHOW(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.SHOW, 0)!; + } + public DATASOURCES(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.DATASOURCES, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_showDataSourcesCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitShowDataSourcesCommand) { + return visitor.visitShowDataSourcesCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class WhereCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public WHERE(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.WHERE, 0)!; + } + public logicalExpression(): LogicalExpressionContext { + return this.getRuleContext(0, LogicalExpressionContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_whereCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitWhereCommand) { + return visitor.visitWhereCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class FieldsCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public FIELDS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.FIELDS, 0)!; + } + public fieldList(): FieldListContext { + return this.getRuleContext(0, FieldListContext)!; + } + public PLUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PLUS, 0); + } + public MINUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUS, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_fieldsCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitFieldsCommand) { + return visitor.visitFieldsCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RenameCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public RENAME(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RENAME, 0)!; + } + public renameClasue(): RenameClasueContext[]; + public renameClasue(i: number): RenameClasueContext | null; + public renameClasue(i?: number): RenameClasueContext[] | RenameClasueContext | null { + if (i === undefined) { + return this.getRuleContexts(RenameClasueContext); + } + + return this.getRuleContext(i, RenameClasueContext); + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_renameCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRenameCommand) { + return visitor.visitRenameCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class StatsCommandContext extends antlr.ParserRuleContext { + public _partitions?: IntegerLiteralContext; + public _allnum?: BooleanLiteralContext; + public _delim?: StringLiteralContext; + public _dedupsplit?: BooleanLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public STATS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.STATS, 0)!; + } + public statsAggTerm(): StatsAggTermContext[]; + public statsAggTerm(i: number): StatsAggTermContext | null; + public statsAggTerm(i?: number): StatsAggTermContext[] | StatsAggTermContext | null { + if (i === undefined) { + return this.getRuleContexts(StatsAggTermContext); + } + + return this.getRuleContext(i, StatsAggTermContext); + } + public PARTITIONS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PARTITIONS, 0); + } + public EQUAL(): antlr.TerminalNode[]; + public EQUAL(i: number): antlr.TerminalNode | null; + public EQUAL(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.EQUAL); + } else { + return this.getToken(OpenSearchPPLParser.EQUAL, i); + } + } + public ALLNUM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ALLNUM, 0); + } + public DELIM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DELIM, 0); + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public statsByClause(): StatsByClauseContext | null { + return this.getRuleContext(0, StatsByClauseContext); + } + public DEDUP_SPLITVALUES(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DEDUP_SPLITVALUES, 0); + } + public integerLiteral(): IntegerLiteralContext | null { + return this.getRuleContext(0, IntegerLiteralContext); + } + public booleanLiteral(): BooleanLiteralContext[]; + public booleanLiteral(i: number): BooleanLiteralContext | null; + public booleanLiteral(i?: number): BooleanLiteralContext[] | BooleanLiteralContext | null { + if (i === undefined) { + return this.getRuleContexts(BooleanLiteralContext); + } + + return this.getRuleContext(i, BooleanLiteralContext); + } + public stringLiteral(): StringLiteralContext | null { + return this.getRuleContext(0, StringLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_statsCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitStatsCommand) { + return visitor.visitStatsCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DedupCommandContext extends antlr.ParserRuleContext { + public _number_?: IntegerLiteralContext; + public _keepempty?: BooleanLiteralContext; + public _consecutive?: BooleanLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public DEDUP(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.DEDUP, 0)!; + } + public fieldList(): FieldListContext { + return this.getRuleContext(0, FieldListContext)!; + } + public KEEPEMPTY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.KEEPEMPTY, 0); + } + public EQUAL(): antlr.TerminalNode[]; + public EQUAL(i: number): antlr.TerminalNode | null; + public EQUAL(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.EQUAL); + } else { + return this.getToken(OpenSearchPPLParser.EQUAL, i); + } + } + public CONSECUTIVE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CONSECUTIVE, 0); + } + public integerLiteral(): IntegerLiteralContext | null { + return this.getRuleContext(0, IntegerLiteralContext); + } + public booleanLiteral(): BooleanLiteralContext[]; + public booleanLiteral(i: number): BooleanLiteralContext | null; + public booleanLiteral(i?: number): BooleanLiteralContext[] | BooleanLiteralContext | null { + if (i === undefined) { + return this.getRuleContexts(BooleanLiteralContext); + } + + return this.getRuleContext(i, BooleanLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_dedupCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDedupCommand) { + return visitor.visitDedupCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SortCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public SORT(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.SORT, 0)!; + } + public sortbyClause(): SortbyClauseContext { + return this.getRuleContext(0, SortbyClauseContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_sortCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSortCommand) { + return visitor.visitSortCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class EvalCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public EVAL(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.EVAL, 0)!; + } + public evalClause(): EvalClauseContext[]; + public evalClause(i: number): EvalClauseContext | null; + public evalClause(i?: number): EvalClauseContext[] | EvalClauseContext | null { + if (i === undefined) { + return this.getRuleContexts(EvalClauseContext); + } + + return this.getRuleContext(i, EvalClauseContext); + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_evalCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitEvalCommand) { + return visitor.visitEvalCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class HeadCommandContext extends antlr.ParserRuleContext { + public _number_?: IntegerLiteralContext; + public _from_?: IntegerLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public HEAD(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.HEAD, 0)!; + } + public FROM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FROM, 0); + } + public integerLiteral(): IntegerLiteralContext[]; + public integerLiteral(i: number): IntegerLiteralContext | null; + public integerLiteral(i?: number): IntegerLiteralContext[] | IntegerLiteralContext | null { + if (i === undefined) { + return this.getRuleContexts(IntegerLiteralContext); + } + + return this.getRuleContext(i, IntegerLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_headCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitHeadCommand) { + return visitor.visitHeadCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TopCommandContext extends antlr.ParserRuleContext { + public _number_?: IntegerLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public TOP(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.TOP, 0)!; + } + public fieldList(): FieldListContext { + return this.getRuleContext(0, FieldListContext)!; + } + public byClause(): ByClauseContext | null { + return this.getRuleContext(0, ByClauseContext); + } + public integerLiteral(): IntegerLiteralContext | null { + return this.getRuleContext(0, IntegerLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_topCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTopCommand) { + return visitor.visitTopCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RareCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public RARE(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RARE, 0)!; + } + public fieldList(): FieldListContext { + return this.getRuleContext(0, FieldListContext)!; + } + public byClause(): ByClauseContext | null { + return this.getRuleContext(0, ByClauseContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_rareCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRareCommand) { + return visitor.visitRareCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class GrokCommandContext extends antlr.ParserRuleContext { + public _source_field?: ExpressionContext; + public _pattern?: StringLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public GROK(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.GROK, 0)!; + } + public expression(): ExpressionContext | null { + return this.getRuleContext(0, ExpressionContext); + } + public stringLiteral(): StringLiteralContext | null { + return this.getRuleContext(0, StringLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_grokCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitGrokCommand) { + return visitor.visitGrokCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ParseCommandContext extends antlr.ParserRuleContext { + public _source_field?: ExpressionContext; + public _pattern?: StringLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public PARSE(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.PARSE, 0)!; + } + public expression(): ExpressionContext | null { + return this.getRuleContext(0, ExpressionContext); + } + public stringLiteral(): StringLiteralContext | null { + return this.getRuleContext(0, StringLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_parseCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitParseCommand) { + return visitor.visitParseCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PatternsCommandContext extends antlr.ParserRuleContext { + public _source_field?: ExpressionContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public PATTERNS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.PATTERNS, 0)!; + } + public patternsParameter(): PatternsParameterContext[]; + public patternsParameter(i: number): PatternsParameterContext | null; + public patternsParameter(i?: number): PatternsParameterContext[] | PatternsParameterContext | null { + if (i === undefined) { + return this.getRuleContexts(PatternsParameterContext); + } + + return this.getRuleContext(i, PatternsParameterContext); + } + public expression(): ExpressionContext | null { + return this.getRuleContext(0, ExpressionContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_patternsCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPatternsCommand) { + return visitor.visitPatternsCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PatternsParameterContext extends antlr.ParserRuleContext { + public _new_field?: StringLiteralContext; + public _pattern?: StringLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public NEW_FIELD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NEW_FIELD, 0); + } + public EQUAL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EQUAL, 0); + } + public stringLiteral(): StringLiteralContext | null { + return this.getRuleContext(0, StringLiteralContext); + } + public PATTERN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PATTERN, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_patternsParameter; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPatternsParameter) { + return visitor.visitPatternsParameter(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PatternsMethodContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public PUNCT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PUNCT, 0); + } + public REGEX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.REGEX, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_patternsMethod; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPatternsMethod) { + return visitor.visitPatternsMethod(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class KmeansCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public KMEANS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.KMEANS, 0)!; + } + public kmeansParameter(): KmeansParameterContext[]; + public kmeansParameter(i: number): KmeansParameterContext | null; + public kmeansParameter(i?: number): KmeansParameterContext[] | KmeansParameterContext | null { + if (i === undefined) { + return this.getRuleContexts(KmeansParameterContext); + } + + return this.getRuleContext(i, KmeansParameterContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_kmeansCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitKmeansCommand) { + return visitor.visitKmeansCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class KmeansParameterContext extends antlr.ParserRuleContext { + public _centroids?: IntegerLiteralContext; + public _iterations?: IntegerLiteralContext; + public _distance_type?: StringLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public CENTROIDS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CENTROIDS, 0); + } + public EQUAL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EQUAL, 0); + } + public integerLiteral(): IntegerLiteralContext | null { + return this.getRuleContext(0, IntegerLiteralContext); + } + public ITERATIONS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ITERATIONS, 0); + } + public DISTANCE_TYPE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DISTANCE_TYPE, 0); + } + public stringLiteral(): StringLiteralContext | null { + return this.getRuleContext(0, StringLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_kmeansParameter; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitKmeansParameter) { + return visitor.visitKmeansParameter(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class AdCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public AD(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.AD, 0)!; + } + public adParameter(): AdParameterContext[]; + public adParameter(i: number): AdParameterContext | null; + public adParameter(i?: number): AdParameterContext[] | AdParameterContext | null { + if (i === undefined) { + return this.getRuleContexts(AdParameterContext); + } + + return this.getRuleContext(i, AdParameterContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_adCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitAdCommand) { + return visitor.visitAdCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class AdParameterContext extends antlr.ParserRuleContext { + public _number_of_trees?: IntegerLiteralContext; + public _shingle_size?: IntegerLiteralContext; + public _sample_size?: IntegerLiteralContext; + public _output_after?: IntegerLiteralContext; + public _time_decay?: DecimalLiteralContext; + public _anomaly_rate?: DecimalLiteralContext; + public _category_field?: StringLiteralContext; + public _time_field?: StringLiteralContext; + public _date_format?: StringLiteralContext; + public _time_zone?: StringLiteralContext; + public _training_data_size?: IntegerLiteralContext; + public _anomaly_score_threshold?: DecimalLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public NUMBER_OF_TREES(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NUMBER_OF_TREES, 0); + } + public EQUAL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EQUAL, 0); + } + public integerLiteral(): IntegerLiteralContext | null { + return this.getRuleContext(0, IntegerLiteralContext); + } + public SHINGLE_SIZE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SHINGLE_SIZE, 0); + } + public SAMPLE_SIZE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SAMPLE_SIZE, 0); + } + public OUTPUT_AFTER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.OUTPUT_AFTER, 0); + } + public TIME_DECAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_DECAY, 0); + } + public decimalLiteral(): DecimalLiteralContext | null { + return this.getRuleContext(0, DecimalLiteralContext); + } + public ANOMALY_RATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ANOMALY_RATE, 0); + } + public CATEGORY_FIELD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CATEGORY_FIELD, 0); + } + public stringLiteral(): StringLiteralContext | null { + return this.getRuleContext(0, StringLiteralContext); + } + public TIME_FIELD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_FIELD, 0); + } + public DATE_FORMAT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATE_FORMAT, 0); + } + public TIME_ZONE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_ZONE, 0); + } + public TRAINING_DATA_SIZE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TRAINING_DATA_SIZE, 0); + } + public ANOMALY_SCORE_THRESHOLD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ANOMALY_SCORE_THRESHOLD, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_adParameter; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitAdParameter) { + return visitor.visitAdParameter(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class MlCommandContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public ML(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.ML, 0)!; + } + public mlArg(): MlArgContext[]; + public mlArg(i: number): MlArgContext | null; + public mlArg(i?: number): MlArgContext[] | MlArgContext | null { + if (i === undefined) { + return this.getRuleContexts(MlArgContext); + } + + return this.getRuleContext(i, MlArgContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_mlCommand; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitMlCommand) { + return visitor.visitMlCommand(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class MlArgContext extends antlr.ParserRuleContext { + public _argName?: IdentContext; + public _argValue?: LiteralValueContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public EQUAL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EQUAL, 0); + } + public ident(): IdentContext | null { + return this.getRuleContext(0, IdentContext); + } + public literalValue(): LiteralValueContext | null { + return this.getRuleContext(0, LiteralValueContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_mlArg; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitMlArg) { + return visitor.visitMlArg(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class FromClauseContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public SOURCE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SOURCE, 0); + } + public EQUAL(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.EQUAL, 0)!; + } + public tableSourceClause(): TableSourceClauseContext | null { + return this.getRuleContext(0, TableSourceClauseContext); + } + public INDEX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.INDEX, 0); + } + public tableFunction(): TableFunctionContext | null { + return this.getRuleContext(0, TableFunctionContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_fromClause; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitFromClause) { + return visitor.visitFromClause(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TableSourceClauseContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public tableSource(): TableSourceContext[]; + public tableSource(i: number): TableSourceContext | null; + public tableSource(i?: number): TableSourceContext[] | TableSourceContext | null { + if (i === undefined) { + return this.getRuleContexts(TableSourceContext); + } + + return this.getRuleContext(i, TableSourceContext); + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_tableSourceClause; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTableSourceClause) { + return visitor.visitTableSourceClause(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RenameClasueContext extends antlr.ParserRuleContext { + public _orignalField?: WcFieldExpressionContext; + public _renamedField?: WcFieldExpressionContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public AS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.AS, 0)!; + } + public wcFieldExpression(): WcFieldExpressionContext[]; + public wcFieldExpression(i: number): WcFieldExpressionContext | null; + public wcFieldExpression(i?: number): WcFieldExpressionContext[] | WcFieldExpressionContext | null { + if (i === undefined) { + return this.getRuleContexts(WcFieldExpressionContext); + } + + return this.getRuleContext(i, WcFieldExpressionContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_renameClasue; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRenameClasue) { + return visitor.visitRenameClasue(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ByClauseContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public BY(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.BY, 0)!; + } + public fieldList(): FieldListContext { + return this.getRuleContext(0, FieldListContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_byClause; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitByClause) { + return visitor.visitByClause(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class StatsByClauseContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public BY(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.BY, 0)!; + } + public fieldList(): FieldListContext | null { + return this.getRuleContext(0, FieldListContext); + } + public bySpanClause(): BySpanClauseContext | null { + return this.getRuleContext(0, BySpanClauseContext); + } + public COMMA(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.COMMA, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_statsByClause; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitStatsByClause) { + return visitor.visitStatsByClause(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class BySpanClauseContext extends antlr.ParserRuleContext { + public _alias?: QualifiedNameContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public spanClause(): SpanClauseContext { + return this.getRuleContext(0, SpanClauseContext)!; + } + public AS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.AS, 0); + } + public qualifiedName(): QualifiedNameContext | null { + return this.getRuleContext(0, QualifiedNameContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_bySpanClause; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitBySpanClause) { + return visitor.visitBySpanClause(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SpanClauseContext extends antlr.ParserRuleContext { + public _value?: LiteralValueContext; + public _unit?: TimespanUnitContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public SPAN(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.SPAN, 0)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public fieldExpression(): FieldExpressionContext { + return this.getRuleContext(0, FieldExpressionContext)!; + } + public COMMA(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.COMMA, 0)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public literalValue(): LiteralValueContext { + return this.getRuleContext(0, LiteralValueContext)!; + } + public timespanUnit(): TimespanUnitContext | null { + return this.getRuleContext(0, TimespanUnitContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_spanClause; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSpanClause) { + return visitor.visitSpanClause(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SortbyClauseContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public sortField(): SortFieldContext[]; + public sortField(i: number): SortFieldContext | null; + public sortField(i?: number): SortFieldContext[] | SortFieldContext | null { + if (i === undefined) { + return this.getRuleContexts(SortFieldContext); + } + + return this.getRuleContext(i, SortFieldContext); + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_sortbyClause; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSortbyClause) { + return visitor.visitSortbyClause(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class EvalClauseContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public fieldExpression(): FieldExpressionContext { + return this.getRuleContext(0, FieldExpressionContext)!; + } + public EQUAL(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.EQUAL, 0)!; + } + public expression(): ExpressionContext { + return this.getRuleContext(0, ExpressionContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_evalClause; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitEvalClause) { + return visitor.visitEvalClause(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class StatsAggTermContext extends antlr.ParserRuleContext { + public _alias?: WcFieldExpressionContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public statsFunction(): StatsFunctionContext { + return this.getRuleContext(0, StatsFunctionContext)!; + } + public AS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.AS, 0); + } + public wcFieldExpression(): WcFieldExpressionContext | null { + return this.getRuleContext(0, WcFieldExpressionContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_statsAggTerm; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitStatsAggTerm) { + return visitor.visitStatsAggTerm(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class StatsFunctionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_statsFunction; + } + public override copyFrom(ctx: StatsFunctionContext): void { + super.copyFrom(ctx); + } +} +export class DistinctCountFunctionCallContext extends StatsFunctionContext { + public constructor(ctx: StatsFunctionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public valueExpression(): ValueExpressionContext { + return this.getRuleContext(0, ValueExpressionContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public DISTINCT_COUNT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DISTINCT_COUNT, 0); + } + public DC(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DC, 0); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDistinctCountFunctionCall) { + return visitor.visitDistinctCountFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class StatsFunctionCallContext extends StatsFunctionContext { + public constructor(ctx: StatsFunctionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public statsFunctionName(): StatsFunctionNameContext { + return this.getRuleContext(0, StatsFunctionNameContext)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public valueExpression(): ValueExpressionContext { + return this.getRuleContext(0, ValueExpressionContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitStatsFunctionCall) { + return visitor.visitStatsFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class CountAllFunctionCallContext extends StatsFunctionContext { + public constructor(ctx: StatsFunctionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public COUNT(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.COUNT, 0)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitCountAllFunctionCall) { + return visitor.visitCountAllFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class PercentileAggFunctionCallContext extends StatsFunctionContext { + public constructor(ctx: StatsFunctionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public percentileAggFunction(): PercentileAggFunctionContext { + return this.getRuleContext(0, PercentileAggFunctionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPercentileAggFunctionCall) { + return visitor.visitPercentileAggFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class TakeAggFunctionCallContext extends StatsFunctionContext { + public constructor(ctx: StatsFunctionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public takeAggFunction(): TakeAggFunctionContext { + return this.getRuleContext(0, TakeAggFunctionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTakeAggFunctionCall) { + return visitor.visitTakeAggFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class StatsFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public AVG(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.AVG, 0); + } + public COUNT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.COUNT, 0); + } + public SUM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SUM, 0); + } + public MIN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MIN, 0); + } + public MAX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MAX, 0); + } + public VAR_SAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.VAR_SAMP, 0); + } + public VAR_POP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.VAR_POP, 0); + } + public STDDEV_SAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STDDEV_SAMP, 0); + } + public STDDEV_POP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STDDEV_POP, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_statsFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitStatsFunctionName) { + return visitor.visitStatsFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TakeAggFunctionContext extends antlr.ParserRuleContext { + public _size?: IntegerLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public TAKE(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.TAKE, 0)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public fieldExpression(): FieldExpressionContext { + return this.getRuleContext(0, FieldExpressionContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public COMMA(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.COMMA, 0); + } + public integerLiteral(): IntegerLiteralContext | null { + return this.getRuleContext(0, IntegerLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_takeAggFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTakeAggFunction) { + return visitor.visitTakeAggFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PercentileAggFunctionContext extends antlr.ParserRuleContext { + public _value?: IntegerLiteralContext; + public _aggField?: FieldExpressionContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public PERCENTILE(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.PERCENTILE, 0)!; + } + public LESS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LESS, 0)!; + } + public GREATER(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.GREATER, 0)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public integerLiteral(): IntegerLiteralContext { + return this.getRuleContext(0, IntegerLiteralContext)!; + } + public fieldExpression(): FieldExpressionContext { + return this.getRuleContext(0, FieldExpressionContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_percentileAggFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPercentileAggFunction) { + return visitor.visitPercentileAggFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public logicalExpression(): LogicalExpressionContext | null { + return this.getRuleContext(0, LogicalExpressionContext); + } + public comparisonExpression(): ComparisonExpressionContext | null { + return this.getRuleContext(0, ComparisonExpressionContext); + } + public valueExpression(): ValueExpressionContext | null { + return this.getRuleContext(0, ValueExpressionContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_expression; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitExpression) { + return visitor.visitExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class LogicalExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_logicalExpression; + } + public override copyFrom(ctx: LogicalExpressionContext): void { + super.copyFrom(ctx); + } +} +export class RelevanceExprContext extends LogicalExpressionContext { + public constructor(ctx: LogicalExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public relevanceExpression(): RelevanceExpressionContext { + return this.getRuleContext(0, RelevanceExpressionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceExpr) { + return visitor.visitRelevanceExpr(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class LogicalNotContext extends LogicalExpressionContext { + public constructor(ctx: LogicalExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public NOT(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.NOT, 0)!; + } + public logicalExpression(): LogicalExpressionContext { + return this.getRuleContext(0, LogicalExpressionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitLogicalNot) { + return visitor.visitLogicalNot(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class BooleanExprContext extends LogicalExpressionContext { + public constructor(ctx: LogicalExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public booleanExpression(): BooleanExpressionContext { + return this.getRuleContext(0, BooleanExpressionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitBooleanExpr) { + return visitor.visitBooleanExpr(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class LogicalAndContext extends LogicalExpressionContext { + public _left?: LogicalExpressionContext; + public _right?: LogicalExpressionContext; + public constructor(ctx: LogicalExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public logicalExpression(): LogicalExpressionContext[]; + public logicalExpression(i: number): LogicalExpressionContext | null; + public logicalExpression(i?: number): LogicalExpressionContext[] | LogicalExpressionContext | null { + if (i === undefined) { + return this.getRuleContexts(LogicalExpressionContext); + } + + return this.getRuleContext(i, LogicalExpressionContext); + } + public AND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.AND, 0); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitLogicalAnd) { + return visitor.visitLogicalAnd(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class ComparsionContext extends LogicalExpressionContext { + public constructor(ctx: LogicalExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public comparisonExpression(): ComparisonExpressionContext { + return this.getRuleContext(0, ComparisonExpressionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitComparsion) { + return visitor.visitComparsion(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class LogicalXorContext extends LogicalExpressionContext { + public _left?: LogicalExpressionContext; + public _right?: LogicalExpressionContext; + public constructor(ctx: LogicalExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public XOR(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.XOR, 0)!; + } + public logicalExpression(): LogicalExpressionContext[]; + public logicalExpression(i: number): LogicalExpressionContext | null; + public logicalExpression(i?: number): LogicalExpressionContext[] | LogicalExpressionContext | null { + if (i === undefined) { + return this.getRuleContexts(LogicalExpressionContext); + } + + return this.getRuleContext(i, LogicalExpressionContext); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitLogicalXor) { + return visitor.visitLogicalXor(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class LogicalOrContext extends LogicalExpressionContext { + public _left?: LogicalExpressionContext; + public _right?: LogicalExpressionContext; + public constructor(ctx: LogicalExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public OR(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.OR, 0)!; + } + public logicalExpression(): LogicalExpressionContext[]; + public logicalExpression(i: number): LogicalExpressionContext | null; + public logicalExpression(i?: number): LogicalExpressionContext[] | LogicalExpressionContext | null { + if (i === undefined) { + return this.getRuleContexts(LogicalExpressionContext); + } + + return this.getRuleContext(i, LogicalExpressionContext); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitLogicalOr) { + return visitor.visitLogicalOr(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ComparisonExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_comparisonExpression; + } + public override copyFrom(ctx: ComparisonExpressionContext): void { + super.copyFrom(ctx); + } +} +export class InExprContext extends ComparisonExpressionContext { + public constructor(ctx: ComparisonExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public valueExpression(): ValueExpressionContext { + return this.getRuleContext(0, ValueExpressionContext)!; + } + public IN(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.IN, 0)!; + } + public valueList(): ValueListContext { + return this.getRuleContext(0, ValueListContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitInExpr) { + return visitor.visitInExpr(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class CompareExprContext extends ComparisonExpressionContext { + public _left?: ValueExpressionContext; + public _right?: ValueExpressionContext; + public constructor(ctx: ComparisonExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public comparisonOperator(): ComparisonOperatorContext { + return this.getRuleContext(0, ComparisonOperatorContext)!; + } + public valueExpression(): ValueExpressionContext[]; + public valueExpression(i: number): ValueExpressionContext | null; + public valueExpression(i?: number): ValueExpressionContext[] | ValueExpressionContext | null { + if (i === undefined) { + return this.getRuleContexts(ValueExpressionContext); + } + + return this.getRuleContext(i, ValueExpressionContext); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitCompareExpr) { + return visitor.visitCompareExpr(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ValueExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_valueExpression; + } + public override copyFrom(ctx: ValueExpressionContext): void { + super.copyFrom(ctx); + } +} +export class PositionFunctionCallContext extends ValueExpressionContext { + public constructor(ctx: ValueExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public positionFunction(): PositionFunctionContext { + return this.getRuleContext(0, PositionFunctionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPositionFunctionCall) { + return visitor.visitPositionFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class ValueExpressionDefaultContext extends ValueExpressionContext { + public constructor(ctx: ValueExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public primaryExpression(): PrimaryExpressionContext { + return this.getRuleContext(0, PrimaryExpressionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitValueExpressionDefault) { + return visitor.visitValueExpressionDefault(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class ParentheticValueExprContext extends ValueExpressionContext { + public constructor(ctx: ValueExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public valueExpression(): ValueExpressionContext { + return this.getRuleContext(0, ValueExpressionContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitParentheticValueExpr) { + return visitor.visitParentheticValueExpr(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class GetFormatFunctionCallContext extends ValueExpressionContext { + public constructor(ctx: ValueExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public getFormatFunction(): GetFormatFunctionContext { + return this.getRuleContext(0, GetFormatFunctionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitGetFormatFunctionCall) { + return visitor.visitGetFormatFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class ExtractFunctionCallContext extends ValueExpressionContext { + public constructor(ctx: ValueExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public extractFunction(): ExtractFunctionContext { + return this.getRuleContext(0, ExtractFunctionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitExtractFunctionCall) { + return visitor.visitExtractFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class BinaryArithmeticContext extends ValueExpressionContext { + public _left?: ValueExpressionContext; + public _binaryOperator?: Token | null; + public _right?: ValueExpressionContext; + public constructor(ctx: ValueExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public valueExpression(): ValueExpressionContext[]; + public valueExpression(i: number): ValueExpressionContext | null; + public valueExpression(i?: number): ValueExpressionContext[] | ValueExpressionContext | null { + if (i === undefined) { + return this.getRuleContexts(ValueExpressionContext); + } + + return this.getRuleContext(i, ValueExpressionContext); + } + public STAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STAR, 0); + } + public DIVIDE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DIVIDE, 0); + } + public MODULE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MODULE, 0); + } + public PLUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PLUS, 0); + } + public MINUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUS, 0); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitBinaryArithmetic) { + return visitor.visitBinaryArithmetic(this); + } else { + return visitor.visitChildren(this); + } + } +} +export class TimestampFunctionCallContext extends ValueExpressionContext { + public constructor(ctx: ValueExpressionContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public timestampFunction(): TimestampFunctionContext { + return this.getRuleContext(0, TimestampFunctionContext)!; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTimestampFunctionCall) { + return visitor.visitTimestampFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PrimaryExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public evalFunctionCall(): EvalFunctionCallContext | null { + return this.getRuleContext(0, EvalFunctionCallContext); + } + public dataTypeFunctionCall(): DataTypeFunctionCallContext | null { + return this.getRuleContext(0, DataTypeFunctionCallContext); + } + public fieldExpression(): FieldExpressionContext | null { + return this.getRuleContext(0, FieldExpressionContext); + } + public literalValue(): LiteralValueContext | null { + return this.getRuleContext(0, LiteralValueContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_primaryExpression; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPrimaryExpression) { + return visitor.visitPrimaryExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PositionFunctionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public positionFunctionName(): PositionFunctionNameContext { + return this.getRuleContext(0, PositionFunctionNameContext)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public functionArg(): FunctionArgContext[]; + public functionArg(i: number): FunctionArgContext | null; + public functionArg(i?: number): FunctionArgContext[] | FunctionArgContext | null { + if (i === undefined) { + return this.getRuleContexts(FunctionArgContext); + } + + return this.getRuleContext(i, FunctionArgContext); + } + public IN(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.IN, 0)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_positionFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPositionFunction) { + return visitor.visitPositionFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class BooleanExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public booleanFunctionCall(): BooleanFunctionCallContext { + return this.getRuleContext(0, BooleanFunctionCallContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_booleanExpression; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitBooleanExpression) { + return visitor.visitBooleanExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RelevanceExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public singleFieldRelevanceFunction(): SingleFieldRelevanceFunctionContext | null { + return this.getRuleContext(0, SingleFieldRelevanceFunctionContext); + } + public multiFieldRelevanceFunction(): MultiFieldRelevanceFunctionContext | null { + return this.getRuleContext(0, MultiFieldRelevanceFunctionContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_relevanceExpression; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceExpression) { + return visitor.visitRelevanceExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SingleFieldRelevanceFunctionContext extends antlr.ParserRuleContext { + public _field?: RelevanceFieldContext; + public _query?: RelevanceQueryContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public singleFieldRelevanceFunctionName(): SingleFieldRelevanceFunctionNameContext { + return this.getRuleContext(0, SingleFieldRelevanceFunctionNameContext)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public relevanceField(): RelevanceFieldContext { + return this.getRuleContext(0, RelevanceFieldContext)!; + } + public relevanceQuery(): RelevanceQueryContext { + return this.getRuleContext(0, RelevanceQueryContext)!; + } + public relevanceArg(): RelevanceArgContext[]; + public relevanceArg(i: number): RelevanceArgContext | null; + public relevanceArg(i?: number): RelevanceArgContext[] | RelevanceArgContext | null { + if (i === undefined) { + return this.getRuleContexts(RelevanceArgContext); + } + + return this.getRuleContext(i, RelevanceArgContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_singleFieldRelevanceFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSingleFieldRelevanceFunction) { + return visitor.visitSingleFieldRelevanceFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class MultiFieldRelevanceFunctionContext extends antlr.ParserRuleContext { + public _field?: RelevanceFieldAndWeightContext; + public _query?: RelevanceQueryContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public multiFieldRelevanceFunctionName(): MultiFieldRelevanceFunctionNameContext { + return this.getRuleContext(0, MultiFieldRelevanceFunctionNameContext)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public LT_SQR_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_SQR_PRTHS, 0)!; + } + public RT_SQR_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_SQR_PRTHS, 0)!; + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public relevanceFieldAndWeight(): RelevanceFieldAndWeightContext[]; + public relevanceFieldAndWeight(i: number): RelevanceFieldAndWeightContext | null; + public relevanceFieldAndWeight(i?: number): RelevanceFieldAndWeightContext[] | RelevanceFieldAndWeightContext | null { + if (i === undefined) { + return this.getRuleContexts(RelevanceFieldAndWeightContext); + } + + return this.getRuleContext(i, RelevanceFieldAndWeightContext); + } + public relevanceQuery(): RelevanceQueryContext { + return this.getRuleContext(0, RelevanceQueryContext)!; + } + public relevanceArg(): RelevanceArgContext[]; + public relevanceArg(i: number): RelevanceArgContext | null; + public relevanceArg(i?: number): RelevanceArgContext[] | RelevanceArgContext | null { + if (i === undefined) { + return this.getRuleContexts(RelevanceArgContext); + } + + return this.getRuleContext(i, RelevanceArgContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_multiFieldRelevanceFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitMultiFieldRelevanceFunction) { + return visitor.visitMultiFieldRelevanceFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TableSourceContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public tableQualifiedName(): TableQualifiedNameContext | null { + return this.getRuleContext(0, TableQualifiedNameContext); + } + public ID_DATE_SUFFIX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ID_DATE_SUFFIX, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_tableSource; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTableSource) { + return visitor.visitTableSource(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TableFunctionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public qualifiedName(): QualifiedNameContext { + return this.getRuleContext(0, QualifiedNameContext)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public functionArgs(): FunctionArgsContext { + return this.getRuleContext(0, FunctionArgsContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_tableFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTableFunction) { + return visitor.visitTableFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class FieldListContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public fieldExpression(): FieldExpressionContext[]; + public fieldExpression(i: number): FieldExpressionContext | null; + public fieldExpression(i?: number): FieldExpressionContext[] | FieldExpressionContext | null { + if (i === undefined) { + return this.getRuleContexts(FieldExpressionContext); + } + + return this.getRuleContext(i, FieldExpressionContext); + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_fieldList; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitFieldList) { + return visitor.visitFieldList(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class WcFieldListContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public wcFieldExpression(): WcFieldExpressionContext[]; + public wcFieldExpression(i: number): WcFieldExpressionContext | null; + public wcFieldExpression(i?: number): WcFieldExpressionContext[] | WcFieldExpressionContext | null { + if (i === undefined) { + return this.getRuleContexts(WcFieldExpressionContext); + } + + return this.getRuleContext(i, WcFieldExpressionContext); + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_wcFieldList; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitWcFieldList) { + return visitor.visitWcFieldList(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SortFieldContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public sortFieldExpression(): SortFieldExpressionContext { + return this.getRuleContext(0, SortFieldExpressionContext)!; + } + public PLUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PLUS, 0); + } + public MINUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUS, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_sortField; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSortField) { + return visitor.visitSortField(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SortFieldExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public fieldExpression(): FieldExpressionContext { + return this.getRuleContext(0, FieldExpressionContext)!; + } + public AUTO(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.AUTO, 0); + } + public LT_PRTHS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0); + } + public RT_PRTHS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0); + } + public STR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STR, 0); + } + public IP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.IP, 0); + } + public NUM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NUM, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_sortFieldExpression; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSortFieldExpression) { + return visitor.visitSortFieldExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class FieldExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public qualifiedName(): QualifiedNameContext { + return this.getRuleContext(0, QualifiedNameContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_fieldExpression; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitFieldExpression) { + return visitor.visitFieldExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class WcFieldExpressionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public wcQualifiedName(): WcQualifiedNameContext { + return this.getRuleContext(0, WcQualifiedNameContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_wcFieldExpression; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitWcFieldExpression) { + return visitor.visitWcFieldExpression(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class EvalFunctionCallContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public evalFunctionName(): EvalFunctionNameContext { + return this.getRuleContext(0, EvalFunctionNameContext)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public functionArgs(): FunctionArgsContext { + return this.getRuleContext(0, FunctionArgsContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_evalFunctionCall; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitEvalFunctionCall) { + return visitor.visitEvalFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DataTypeFunctionCallContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public CAST(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.CAST, 0)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public expression(): ExpressionContext { + return this.getRuleContext(0, ExpressionContext)!; + } + public AS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.AS, 0)!; + } + public convertedDataType(): ConvertedDataTypeContext { + return this.getRuleContext(0, ConvertedDataTypeContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_dataTypeFunctionCall; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDataTypeFunctionCall) { + return visitor.visitDataTypeFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class BooleanFunctionCallContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public conditionFunctionBase(): ConditionFunctionBaseContext { + return this.getRuleContext(0, ConditionFunctionBaseContext)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public functionArgs(): FunctionArgsContext { + return this.getRuleContext(0, FunctionArgsContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_booleanFunctionCall; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitBooleanFunctionCall) { + return visitor.visitBooleanFunctionCall(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ConvertedDataTypeContext extends antlr.ParserRuleContext { + public _typeName?: Token | null; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public DATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATE, 0); + } + public TIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME, 0); + } + public TIMESTAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIMESTAMP, 0); + } + public INT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.INT, 0); + } + public INTEGER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.INTEGER, 0); + } + public DOUBLE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DOUBLE, 0); + } + public LONG(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LONG, 0); + } + public FLOAT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FLOAT, 0); + } + public STRING(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STRING, 0); + } + public BOOLEAN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.BOOLEAN, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_convertedDataType; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitConvertedDataType) { + return visitor.visitConvertedDataType(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class EvalFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public mathematicalFunctionName(): MathematicalFunctionNameContext | null { + return this.getRuleContext(0, MathematicalFunctionNameContext); + } + public dateTimeFunctionName(): DateTimeFunctionNameContext | null { + return this.getRuleContext(0, DateTimeFunctionNameContext); + } + public textFunctionName(): TextFunctionNameContext | null { + return this.getRuleContext(0, TextFunctionNameContext); + } + public conditionFunctionBase(): ConditionFunctionBaseContext | null { + return this.getRuleContext(0, ConditionFunctionBaseContext); + } + public systemFunctionName(): SystemFunctionNameContext | null { + return this.getRuleContext(0, SystemFunctionNameContext); + } + public positionFunctionName(): PositionFunctionNameContext | null { + return this.getRuleContext(0, PositionFunctionNameContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_evalFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitEvalFunctionName) { + return visitor.visitEvalFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class FunctionArgsContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public functionArg(): FunctionArgContext[]; + public functionArg(i: number): FunctionArgContext | null; + public functionArg(i?: number): FunctionArgContext[] | FunctionArgContext | null { + if (i === undefined) { + return this.getRuleContexts(FunctionArgContext); + } + + return this.getRuleContext(i, FunctionArgContext); + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_functionArgs; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitFunctionArgs) { + return visitor.visitFunctionArgs(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class FunctionArgContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public valueExpression(): ValueExpressionContext { + return this.getRuleContext(0, ValueExpressionContext)!; + } + public ident(): IdentContext | null { + return this.getRuleContext(0, IdentContext); + } + public EQUAL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EQUAL, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_functionArg; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitFunctionArg) { + return visitor.visitFunctionArg(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RelevanceArgContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public relevanceArgName(): RelevanceArgNameContext { + return this.getRuleContext(0, RelevanceArgNameContext)!; + } + public EQUAL(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.EQUAL, 0)!; + } + public relevanceArgValue(): RelevanceArgValueContext { + return this.getRuleContext(0, RelevanceArgValueContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_relevanceArg; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceArg) { + return visitor.visitRelevanceArg(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RelevanceArgNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public ALLOW_LEADING_WILDCARD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ALLOW_LEADING_WILDCARD, 0); + } + public ANALYZER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ANALYZER, 0); + } + public ANALYZE_WILDCARD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ANALYZE_WILDCARD, 0); + } + public AUTO_GENERATE_SYNONYMS_PHRASE_QUERY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.AUTO_GENERATE_SYNONYMS_PHRASE_QUERY, 0); + } + public BOOST(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.BOOST, 0); + } + public CUTOFF_FREQUENCY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CUTOFF_FREQUENCY, 0); + } + public DEFAULT_FIELD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DEFAULT_FIELD, 0); + } + public DEFAULT_OPERATOR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DEFAULT_OPERATOR, 0); + } + public ENABLE_POSITION_INCREMENTS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ENABLE_POSITION_INCREMENTS, 0); + } + public ESCAPE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ESCAPE, 0); + } + public FIELDS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FIELDS, 0); + } + public FLAGS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FLAGS, 0); + } + public FUZZINESS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FUZZINESS, 0); + } + public FUZZY_MAX_EXPANSIONS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FUZZY_MAX_EXPANSIONS, 0); + } + public FUZZY_PREFIX_LENGTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FUZZY_PREFIX_LENGTH, 0); + } + public FUZZY_REWRITE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FUZZY_REWRITE, 0); + } + public FUZZY_TRANSPOSITIONS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FUZZY_TRANSPOSITIONS, 0); + } + public LENIENT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LENIENT, 0); + } + public LOW_FREQ_OPERATOR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LOW_FREQ_OPERATOR, 0); + } + public MAX_DETERMINIZED_STATES(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MAX_DETERMINIZED_STATES, 0); + } + public MAX_EXPANSIONS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MAX_EXPANSIONS, 0); + } + public MINIMUM_SHOULD_MATCH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINIMUM_SHOULD_MATCH, 0); + } + public OPERATOR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.OPERATOR, 0); + } + public PHRASE_SLOP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PHRASE_SLOP, 0); + } + public PREFIX_LENGTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PREFIX_LENGTH, 0); + } + public QUOTE_ANALYZER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.QUOTE_ANALYZER, 0); + } + public QUOTE_FIELD_SUFFIX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.QUOTE_FIELD_SUFFIX, 0); + } + public REWRITE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.REWRITE, 0); + } + public SLOP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SLOP, 0); + } + public TIE_BREAKER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIE_BREAKER, 0); + } + public TIME_ZONE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_ZONE, 0); + } + public TYPE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TYPE, 0); + } + public ZERO_TERMS_QUERY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ZERO_TERMS_QUERY, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_relevanceArgName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceArgName) { + return visitor.visitRelevanceArgName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RelevanceFieldAndWeightContext extends antlr.ParserRuleContext { + public _field?: RelevanceFieldContext; + public _weight?: RelevanceFieldWeightContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public relevanceField(): RelevanceFieldContext { + return this.getRuleContext(0, RelevanceFieldContext)!; + } + public relevanceFieldWeight(): RelevanceFieldWeightContext | null { + return this.getRuleContext(0, RelevanceFieldWeightContext); + } + public BIT_XOR_OP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.BIT_XOR_OP, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_relevanceFieldAndWeight; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceFieldAndWeight) { + return visitor.visitRelevanceFieldAndWeight(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RelevanceFieldWeightContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public integerLiteral(): IntegerLiteralContext | null { + return this.getRuleContext(0, IntegerLiteralContext); + } + public decimalLiteral(): DecimalLiteralContext | null { + return this.getRuleContext(0, DecimalLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_relevanceFieldWeight; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceFieldWeight) { + return visitor.visitRelevanceFieldWeight(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RelevanceFieldContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public qualifiedName(): QualifiedNameContext | null { + return this.getRuleContext(0, QualifiedNameContext); + } + public stringLiteral(): StringLiteralContext | null { + return this.getRuleContext(0, StringLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_relevanceField; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceField) { + return visitor.visitRelevanceField(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RelevanceQueryContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public relevanceArgValue(): RelevanceArgValueContext { + return this.getRuleContext(0, RelevanceArgValueContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_relevanceQuery; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceQuery) { + return visitor.visitRelevanceQuery(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class RelevanceArgValueContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public qualifiedName(): QualifiedNameContext | null { + return this.getRuleContext(0, QualifiedNameContext); + } + public literalValue(): LiteralValueContext | null { + return this.getRuleContext(0, LiteralValueContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_relevanceArgValue; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitRelevanceArgValue) { + return visitor.visitRelevanceArgValue(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class MathematicalFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public ABS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ABS, 0); + } + public CBRT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CBRT, 0); + } + public CEIL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CEIL, 0); + } + public CEILING(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CEILING, 0); + } + public CONV(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CONV, 0); + } + public CRC32(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CRC32, 0); + } + public E(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.E, 0); + } + public EXP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EXP, 0); + } + public FLOOR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FLOOR, 0); + } + public LN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LN, 0); + } + public LOG(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LOG, 0); + } + public LOG10(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LOG10, 0); + } + public LOG2(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LOG2, 0); + } + public MOD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MOD, 0); + } + public PI(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PI, 0); + } + public POW(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.POW, 0); + } + public POWER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.POWER, 0); + } + public RAND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RAND, 0); + } + public ROUND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ROUND, 0); + } + public SIGN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SIGN, 0); + } + public SQRT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SQRT, 0); + } + public TRUNCATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TRUNCATE, 0); + } + public trigonometricFunctionName(): TrigonometricFunctionNameContext | null { + return this.getRuleContext(0, TrigonometricFunctionNameContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_mathematicalFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitMathematicalFunctionName) { + return visitor.visitMathematicalFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TrigonometricFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public ACOS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ACOS, 0); + } + public ASIN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ASIN, 0); + } + public ATAN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ATAN, 0); + } + public ATAN2(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ATAN2, 0); + } + public COS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.COS, 0); + } + public COT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.COT, 0); + } + public DEGREES(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DEGREES, 0); + } + public RADIANS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RADIANS, 0); + } + public SIN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SIN, 0); + } + public TAN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TAN, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_trigonometricFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTrigonometricFunctionName) { + return visitor.visitTrigonometricFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DateTimeFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public ADDDATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ADDDATE, 0); + } + public ADDTIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ADDTIME, 0); + } + public CONVERT_TZ(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CONVERT_TZ, 0); + } + public CURDATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CURDATE, 0); + } + public CURRENT_DATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CURRENT_DATE, 0); + } + public CURRENT_TIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CURRENT_TIME, 0); + } + public CURRENT_TIMESTAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CURRENT_TIMESTAMP, 0); + } + public CURTIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CURTIME, 0); + } + public DATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATE, 0); + } + public DATEDIFF(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATEDIFF, 0); + } + public DATETIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATETIME, 0); + } + public DATE_ADD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATE_ADD, 0); + } + public DATE_FORMAT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATE_FORMAT, 0); + } + public DATE_SUB(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATE_SUB, 0); + } + public DAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY, 0); + } + public DAYNAME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAYNAME, 0); + } + public DAYOFMONTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAYOFMONTH, 0); + } + public DAYOFWEEK(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAYOFWEEK, 0); + } + public DAYOFYEAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAYOFYEAR, 0); + } + public DAY_OF_MONTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_OF_MONTH, 0); + } + public DAY_OF_WEEK(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_OF_WEEK, 0); + } + public DAY_OF_YEAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_OF_YEAR, 0); + } + public FROM_DAYS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FROM_DAYS, 0); + } + public FROM_UNIXTIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FROM_UNIXTIME, 0); + } + public HOUR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR, 0); + } + public HOUR_OF_DAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR_OF_DAY, 0); + } + public LAST_DAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LAST_DAY, 0); + } + public LOCALTIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LOCALTIME, 0); + } + public LOCALTIMESTAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LOCALTIMESTAMP, 0); + } + public MAKEDATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MAKEDATE, 0); + } + public MAKETIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MAKETIME, 0); + } + public MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MICROSECOND, 0); + } + public MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE, 0); + } + public MINUTE_OF_DAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE_OF_DAY, 0); + } + public MINUTE_OF_HOUR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE_OF_HOUR, 0); + } + public MONTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MONTH, 0); + } + public MONTHNAME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MONTHNAME, 0); + } + public MONTH_OF_YEAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MONTH_OF_YEAR, 0); + } + public NOW(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NOW, 0); + } + public PERIOD_ADD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PERIOD_ADD, 0); + } + public PERIOD_DIFF(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PERIOD_DIFF, 0); + } + public QUARTER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.QUARTER, 0); + } + public SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SECOND, 0); + } + public SECOND_OF_MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SECOND_OF_MINUTE, 0); + } + public SEC_TO_TIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SEC_TO_TIME, 0); + } + public STR_TO_DATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STR_TO_DATE, 0); + } + public SUBDATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SUBDATE, 0); + } + public SUBTIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SUBTIME, 0); + } + public SYSDATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SYSDATE, 0); + } + public TIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME, 0); + } + public TIMEDIFF(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIMEDIFF, 0); + } + public TIMESTAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIMESTAMP, 0); + } + public TIME_FORMAT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_FORMAT, 0); + } + public TIME_TO_SEC(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_TO_SEC, 0); + } + public TO_DAYS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TO_DAYS, 0); + } + public TO_SECONDS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TO_SECONDS, 0); + } + public UNIX_TIMESTAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.UNIX_TIMESTAMP, 0); + } + public UTC_DATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.UTC_DATE, 0); + } + public UTC_TIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.UTC_TIME, 0); + } + public UTC_TIMESTAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.UTC_TIMESTAMP, 0); + } + public WEEK(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.WEEK, 0); + } + public WEEKDAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.WEEKDAY, 0); + } + public WEEK_OF_YEAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.WEEK_OF_YEAR, 0); + } + public YEAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.YEAR, 0); + } + public YEARWEEK(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.YEARWEEK, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_dateTimeFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDateTimeFunctionName) { + return visitor.visitDateTimeFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class GetFormatFunctionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public GET_FORMAT(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.GET_FORMAT, 0)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public getFormatType(): GetFormatTypeContext { + return this.getRuleContext(0, GetFormatTypeContext)!; + } + public COMMA(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.COMMA, 0)!; + } + public functionArg(): FunctionArgContext { + return this.getRuleContext(0, FunctionArgContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_getFormatFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitGetFormatFunction) { + return visitor.visitGetFormatFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class GetFormatTypeContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public DATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATE, 0); + } + public DATETIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATETIME, 0); + } + public TIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME, 0); + } + public TIMESTAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIMESTAMP, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_getFormatType; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitGetFormatType) { + return visitor.visitGetFormatType(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ExtractFunctionContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public EXTRACT(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.EXTRACT, 0)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public datetimePart(): DatetimePartContext { + return this.getRuleContext(0, DatetimePartContext)!; + } + public FROM(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.FROM, 0)!; + } + public functionArg(): FunctionArgContext { + return this.getRuleContext(0, FunctionArgContext)!; + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_extractFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitExtractFunction) { + return visitor.visitExtractFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SimpleDateTimePartContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MICROSECOND, 0); + } + public SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SECOND, 0); + } + public MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE, 0); + } + public HOUR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR, 0); + } + public DAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY, 0); + } + public WEEK(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.WEEK, 0); + } + public MONTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MONTH, 0); + } + public QUARTER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.QUARTER, 0); + } + public YEAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.YEAR, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_simpleDateTimePart; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSimpleDateTimePart) { + return visitor.visitSimpleDateTimePart(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ComplexDateTimePartContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public SECOND_MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SECOND_MICROSECOND, 0); + } + public MINUTE_MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE_MICROSECOND, 0); + } + public MINUTE_SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE_SECOND, 0); + } + public HOUR_MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR_MICROSECOND, 0); + } + public HOUR_SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR_SECOND, 0); + } + public HOUR_MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR_MINUTE, 0); + } + public DAY_MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_MICROSECOND, 0); + } + public DAY_SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_SECOND, 0); + } + public DAY_MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_MINUTE, 0); + } + public DAY_HOUR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_HOUR, 0); + } + public YEAR_MONTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.YEAR_MONTH, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_complexDateTimePart; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitComplexDateTimePart) { + return visitor.visitComplexDateTimePart(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DatetimePartContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public simpleDateTimePart(): SimpleDateTimePartContext | null { + return this.getRuleContext(0, SimpleDateTimePartContext); + } + public complexDateTimePart(): ComplexDateTimePartContext | null { + return this.getRuleContext(0, ComplexDateTimePartContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_datetimePart; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDatetimePart) { + return visitor.visitDatetimePart(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TimestampFunctionContext extends antlr.ParserRuleContext { + public _firstArg?: FunctionArgContext; + public _secondArg?: FunctionArgContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public timestampFunctionName(): TimestampFunctionNameContext { + return this.getRuleContext(0, TimestampFunctionNameContext)!; + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public simpleDateTimePart(): SimpleDateTimePartContext { + return this.getRuleContext(0, SimpleDateTimePartContext)!; + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public functionArg(): FunctionArgContext[]; + public functionArg(i: number): FunctionArgContext | null; + public functionArg(i?: number): FunctionArgContext[] | FunctionArgContext | null { + if (i === undefined) { + return this.getRuleContexts(FunctionArgContext); + } + + return this.getRuleContext(i, FunctionArgContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_timestampFunction; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTimestampFunction) { + return visitor.visitTimestampFunction(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TimestampFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public TIMESTAMPADD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIMESTAMPADD, 0); + } + public TIMESTAMPDIFF(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIMESTAMPDIFF, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_timestampFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTimestampFunctionName) { + return visitor.visitTimestampFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ConditionFunctionBaseContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public LIKE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LIKE, 0); + } + public IF(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.IF, 0); + } + public ISNULL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ISNULL, 0); + } + public ISNOTNULL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ISNOTNULL, 0); + } + public IFNULL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.IFNULL, 0); + } + public NULLIF(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NULLIF, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_conditionFunctionBase; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitConditionFunctionBase) { + return visitor.visitConditionFunctionBase(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SystemFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public TYPEOF(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.TYPEOF, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_systemFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSystemFunctionName) { + return visitor.visitSystemFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TextFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public SUBSTR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SUBSTR, 0); + } + public SUBSTRING(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SUBSTRING, 0); + } + public TRIM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TRIM, 0); + } + public LTRIM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LTRIM, 0); + } + public RTRIM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RTRIM, 0); + } + public LOWER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LOWER, 0); + } + public UPPER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.UPPER, 0); + } + public CONCAT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CONCAT, 0); + } + public CONCAT_WS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CONCAT_WS, 0); + } + public LENGTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LENGTH, 0); + } + public STRCMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STRCMP, 0); + } + public RIGHT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RIGHT, 0); + } + public LEFT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LEFT, 0); + } + public ASCII(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ASCII, 0); + } + public LOCATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LOCATE, 0); + } + public REPLACE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.REPLACE, 0); + } + public REVERSE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.REVERSE, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_textFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTextFunctionName) { + return visitor.visitTextFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class PositionFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public POSITION(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.POSITION, 0)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_positionFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitPositionFunctionName) { + return visitor.visitPositionFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ComparisonOperatorContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public EQUAL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EQUAL, 0); + } + public NOT_EQUAL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NOT_EQUAL, 0); + } + public LESS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LESS, 0); + } + public NOT_LESS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NOT_LESS, 0); + } + public GREATER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.GREATER, 0); + } + public NOT_GREATER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NOT_GREATER, 0); + } + public REGEXP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.REGEXP, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_comparisonOperator; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitComparisonOperator) { + return visitor.visitComparisonOperator(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class SingleFieldRelevanceFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public MATCH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MATCH, 0); + } + public MATCH_PHRASE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MATCH_PHRASE, 0); + } + public MATCH_BOOL_PREFIX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MATCH_BOOL_PREFIX, 0); + } + public MATCH_PHRASE_PREFIX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MATCH_PHRASE_PREFIX, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_singleFieldRelevanceFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitSingleFieldRelevanceFunctionName) { + return visitor.visitSingleFieldRelevanceFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class MultiFieldRelevanceFunctionNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public SIMPLE_QUERY_STRING(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SIMPLE_QUERY_STRING, 0); + } + public MULTI_MATCH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MULTI_MATCH, 0); + } + public QUERY_STRING(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.QUERY_STRING, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_multiFieldRelevanceFunctionName; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitMultiFieldRelevanceFunctionName) { + return visitor.visitMultiFieldRelevanceFunctionName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class LiteralValueContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public intervalLiteral(): IntervalLiteralContext | null { + return this.getRuleContext(0, IntervalLiteralContext); + } + public stringLiteral(): StringLiteralContext | null { + return this.getRuleContext(0, StringLiteralContext); + } + public integerLiteral(): IntegerLiteralContext | null { + return this.getRuleContext(0, IntegerLiteralContext); + } + public decimalLiteral(): DecimalLiteralContext | null { + return this.getRuleContext(0, DecimalLiteralContext); + } + public booleanLiteral(): BooleanLiteralContext | null { + return this.getRuleContext(0, BooleanLiteralContext); + } + public datetimeLiteral(): DatetimeLiteralContext | null { + return this.getRuleContext(0, DatetimeLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_literalValue; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitLiteralValue) { + return visitor.visitLiteralValue(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class IntervalLiteralContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public INTERVAL(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.INTERVAL, 0)!; + } + public valueExpression(): ValueExpressionContext { + return this.getRuleContext(0, ValueExpressionContext)!; + } + public intervalUnit(): IntervalUnitContext { + return this.getRuleContext(0, IntervalUnitContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_intervalLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitIntervalLiteral) { + return visitor.visitIntervalLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class StringLiteralContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public DQUOTA_STRING(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DQUOTA_STRING, 0); + } + public SQUOTA_STRING(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SQUOTA_STRING, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_stringLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitStringLiteral) { + return visitor.visitStringLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class IntegerLiteralContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public INTEGER_LITERAL(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.INTEGER_LITERAL, 0)!; + } + public PLUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PLUS, 0); + } + public MINUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUS, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_integerLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitIntegerLiteral) { + return visitor.visitIntegerLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DecimalLiteralContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public DECIMAL_LITERAL(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.DECIMAL_LITERAL, 0)!; + } + public PLUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PLUS, 0); + } + public MINUS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUS, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_decimalLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDecimalLiteral) { + return visitor.visitDecimalLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class BooleanLiteralContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public TRUE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TRUE, 0); + } + public FALSE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FALSE, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_booleanLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitBooleanLiteral) { + return visitor.visitBooleanLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DatetimeLiteralContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public dateLiteral(): DateLiteralContext | null { + return this.getRuleContext(0, DateLiteralContext); + } + public timeLiteral(): TimeLiteralContext | null { + return this.getRuleContext(0, TimeLiteralContext); + } + public timestampLiteral(): TimestampLiteralContext | null { + return this.getRuleContext(0, TimestampLiteralContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_datetimeLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDatetimeLiteral) { + return visitor.visitDatetimeLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class DateLiteralContext extends antlr.ParserRuleContext { + public _date?: StringLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public DATE(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.DATE, 0)!; + } + public stringLiteral(): StringLiteralContext { + return this.getRuleContext(0, StringLiteralContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_dateLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitDateLiteral) { + return visitor.visitDateLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TimeLiteralContext extends antlr.ParserRuleContext { + public _time?: StringLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public TIME(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.TIME, 0)!; + } + public stringLiteral(): StringLiteralContext { + return this.getRuleContext(0, StringLiteralContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_timeLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTimeLiteral) { + return visitor.visitTimeLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TimestampLiteralContext extends antlr.ParserRuleContext { + public _timestamp?: StringLiteralContext; + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public TIMESTAMP(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.TIMESTAMP, 0)!; + } + public stringLiteral(): StringLiteralContext { + return this.getRuleContext(0, StringLiteralContext)!; + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_timestampLiteral; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTimestampLiteral) { + return visitor.visitTimestampLiteral(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class IntervalUnitContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MICROSECOND, 0); + } + public SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SECOND, 0); + } + public MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE, 0); + } + public HOUR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR, 0); + } + public DAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY, 0); + } + public WEEK(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.WEEK, 0); + } + public MONTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MONTH, 0); + } + public QUARTER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.QUARTER, 0); + } + public YEAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.YEAR, 0); + } + public SECOND_MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SECOND_MICROSECOND, 0); + } + public MINUTE_MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE_MICROSECOND, 0); + } + public MINUTE_SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE_SECOND, 0); + } + public HOUR_MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR_MICROSECOND, 0); + } + public HOUR_SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR_SECOND, 0); + } + public HOUR_MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR_MINUTE, 0); + } + public DAY_MICROSECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_MICROSECOND, 0); + } + public DAY_SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_SECOND, 0); + } + public DAY_MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_MINUTE, 0); + } + public DAY_HOUR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY_HOUR, 0); + } + public YEAR_MONTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.YEAR_MONTH, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_intervalUnit; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitIntervalUnit) { + return visitor.visitIntervalUnit(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TimespanUnitContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public MS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MS, 0); + } + public S(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.S, 0); + } + public M(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.M, 0); + } + public H(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.H, 0); + } + public D(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.D, 0); + } + public W(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.W, 0); + } + public Q(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.Q, 0); + } + public Y(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.Y, 0); + } + public MILLISECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MILLISECOND, 0); + } + public SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SECOND, 0); + } + public MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MINUTE, 0); + } + public HOUR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HOUR, 0); + } + public DAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DAY, 0); + } + public WEEK(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.WEEK, 0); + } + public MONTH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MONTH, 0); + } + public QUARTER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.QUARTER, 0); + } + public YEAR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.YEAR, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_timespanUnit; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTimespanUnit) { + return visitor.visitTimespanUnit(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class ValueListContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public LT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.LT_PRTHS, 0)!; + } + public literalValue(): LiteralValueContext[]; + public literalValue(i: number): LiteralValueContext | null; + public literalValue(i?: number): LiteralValueContext[] | LiteralValueContext | null { + if (i === undefined) { + return this.getRuleContexts(LiteralValueContext); + } + + return this.getRuleContext(i, LiteralValueContext); + } + public RT_PRTHS(): antlr.TerminalNode { + return this.getToken(OpenSearchPPLParser.RT_PRTHS, 0)!; + } + public COMMA(): antlr.TerminalNode[]; + public COMMA(i: number): antlr.TerminalNode | null; + public COMMA(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.COMMA); + } else { + return this.getToken(OpenSearchPPLParser.COMMA, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_valueList; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitValueList) { + return visitor.visitValueList(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class QualifiedNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_qualifiedName; + } + public override copyFrom(ctx: QualifiedNameContext): void { + super.copyFrom(ctx); + } +} +export class IdentsAsQualifiedNameContext extends QualifiedNameContext { + public constructor(ctx: QualifiedNameContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public ident(): IdentContext[]; + public ident(i: number): IdentContext | null; + public ident(i?: number): IdentContext[] | IdentContext | null { + if (i === undefined) { + return this.getRuleContexts(IdentContext); + } + + return this.getRuleContext(i, IdentContext); + } + public DOT(): antlr.TerminalNode[]; + public DOT(i: number): antlr.TerminalNode | null; + public DOT(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.DOT); + } else { + return this.getToken(OpenSearchPPLParser.DOT, i); + } + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitIdentsAsQualifiedName) { + return visitor.visitIdentsAsQualifiedName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TableQualifiedNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_tableQualifiedName; + } + public override copyFrom(ctx: TableQualifiedNameContext): void { + super.copyFrom(ctx); + } +} +export class IdentsAsTableQualifiedNameContext extends TableQualifiedNameContext { + public constructor(ctx: TableQualifiedNameContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public tableIdent(): TableIdentContext { + return this.getRuleContext(0, TableIdentContext)!; + } + public DOT(): antlr.TerminalNode[]; + public DOT(i: number): antlr.TerminalNode | null; + public DOT(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.DOT); + } else { + return this.getToken(OpenSearchPPLParser.DOT, i); + } + } + public ident(): IdentContext[]; + public ident(i: number): IdentContext | null; + public ident(i?: number): IdentContext[] | IdentContext | null { + if (i === undefined) { + return this.getRuleContexts(IdentContext); + } + + return this.getRuleContext(i, IdentContext); + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitIdentsAsTableQualifiedName) { + return visitor.visitIdentsAsTableQualifiedName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class WcQualifiedNameContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_wcQualifiedName; + } + public override copyFrom(ctx: WcQualifiedNameContext): void { + super.copyFrom(ctx); + } +} +export class IdentsAsWildcardQualifiedNameContext extends WcQualifiedNameContext { + public constructor(ctx: WcQualifiedNameContext) { + super(ctx.parent, ctx.invokingState); + super.copyFrom(ctx); + } + public wildcard(): WildcardContext[]; + public wildcard(i: number): WildcardContext | null; + public wildcard(i?: number): WildcardContext[] | WildcardContext | null { + if (i === undefined) { + return this.getRuleContexts(WildcardContext); + } + + return this.getRuleContext(i, WildcardContext); + } + public DOT(): antlr.TerminalNode[]; + public DOT(i: number): antlr.TerminalNode | null; + public DOT(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.DOT); + } else { + return this.getToken(OpenSearchPPLParser.DOT, i); + } + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitIdentsAsWildcardQualifiedName) { + return visitor.visitIdentsAsWildcardQualifiedName(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class IdentContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public ID(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ID, 0); + } + public DOT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DOT, 0); + } + public BACKTICK(): antlr.TerminalNode[]; + public BACKTICK(i: number): antlr.TerminalNode | null; + public BACKTICK(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.BACKTICK); + } else { + return this.getToken(OpenSearchPPLParser.BACKTICK, i); + } + } + public ident(): IdentContext | null { + return this.getRuleContext(0, IdentContext); + } + public BQUOTA_STRING(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.BQUOTA_STRING, 0); + } + public keywordsCanBeId(): KeywordsCanBeIdContext | null { + return this.getRuleContext(0, KeywordsCanBeIdContext); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_ident; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitIdent) { + return visitor.visitIdent(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class TableIdentContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public ident(): IdentContext { + return this.getRuleContext(0, IdentContext)!; + } + public CLUSTER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CLUSTER, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_tableIdent; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitTableIdent) { + return visitor.visitTableIdent(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class WildcardContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public ident(): IdentContext[]; + public ident(i: number): IdentContext | null; + public ident(i?: number): IdentContext[] | IdentContext | null { + if (i === undefined) { + return this.getRuleContexts(IdentContext); + } + + return this.getRuleContext(i, IdentContext); + } + public MODULE(): antlr.TerminalNode[]; + public MODULE(i: number): antlr.TerminalNode | null; + public MODULE(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.MODULE); + } else { + return this.getToken(OpenSearchPPLParser.MODULE, i); + } + } + public SINGLE_QUOTE(): antlr.TerminalNode[]; + public SINGLE_QUOTE(i: number): antlr.TerminalNode | null; + public SINGLE_QUOTE(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.SINGLE_QUOTE); + } else { + return this.getToken(OpenSearchPPLParser.SINGLE_QUOTE, i); + } + } + public wildcard(): WildcardContext | null { + return this.getRuleContext(0, WildcardContext); + } + public DOUBLE_QUOTE(): antlr.TerminalNode[]; + public DOUBLE_QUOTE(i: number): antlr.TerminalNode | null; + public DOUBLE_QUOTE(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.DOUBLE_QUOTE); + } else { + return this.getToken(OpenSearchPPLParser.DOUBLE_QUOTE, i); + } + } + public BACKTICK(): antlr.TerminalNode[]; + public BACKTICK(i: number): antlr.TerminalNode | null; + public BACKTICK(i?: number): antlr.TerminalNode | null | antlr.TerminalNode[] { + if (i === undefined) { + return this.getTokens(OpenSearchPPLParser.BACKTICK); + } else { + return this.getToken(OpenSearchPPLParser.BACKTICK, i); + } + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_wildcard; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitWildcard) { + return visitor.visitWildcard(this); + } else { + return visitor.visitChildren(this); + } + } +} + + +export class KeywordsCanBeIdContext extends antlr.ParserRuleContext { + public constructor(parent: antlr.ParserRuleContext | null, invokingState: number) { + super(parent, invokingState); + } + public D(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.D, 0); + } + public timespanUnit(): TimespanUnitContext | null { + return this.getRuleContext(0, TimespanUnitContext); + } + public SPAN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SPAN, 0); + } + public evalFunctionName(): EvalFunctionNameContext | null { + return this.getRuleContext(0, EvalFunctionNameContext); + } + public relevanceArgName(): RelevanceArgNameContext | null { + return this.getRuleContext(0, RelevanceArgNameContext); + } + public intervalUnit(): IntervalUnitContext | null { + return this.getRuleContext(0, IntervalUnitContext); + } + public dateTimeFunctionName(): DateTimeFunctionNameContext | null { + return this.getRuleContext(0, DateTimeFunctionNameContext); + } + public textFunctionName(): TextFunctionNameContext | null { + return this.getRuleContext(0, TextFunctionNameContext); + } + public mathematicalFunctionName(): MathematicalFunctionNameContext | null { + return this.getRuleContext(0, MathematicalFunctionNameContext); + } + public positionFunctionName(): PositionFunctionNameContext | null { + return this.getRuleContext(0, PositionFunctionNameContext); + } + public SEARCH(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SEARCH, 0); + } + public DESCRIBE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DESCRIBE, 0); + } + public SHOW(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SHOW, 0); + } + public FROM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FROM, 0); + } + public WHERE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.WHERE, 0); + } + public FIELDS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FIELDS, 0); + } + public RENAME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RENAME, 0); + } + public STATS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STATS, 0); + } + public DEDUP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DEDUP, 0); + } + public SORT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SORT, 0); + } + public EVAL(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EVAL, 0); + } + public HEAD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.HEAD, 0); + } + public TOP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TOP, 0); + } + public RARE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RARE, 0); + } + public PARSE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PARSE, 0); + } + public METHOD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.METHOD, 0); + } + public REGEX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.REGEX, 0); + } + public PUNCT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PUNCT, 0); + } + public GROK(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.GROK, 0); + } + public PATTERN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PATTERN, 0); + } + public PATTERNS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PATTERNS, 0); + } + public NEW_FIELD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NEW_FIELD, 0); + } + public KMEANS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.KMEANS, 0); + } + public AD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.AD, 0); + } + public ML(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ML, 0); + } + public SOURCE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SOURCE, 0); + } + public INDEX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.INDEX, 0); + } + public DESC(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DESC, 0); + } + public DATASOURCES(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DATASOURCES, 0); + } + public SORTBY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SORTBY, 0); + } + public STR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STR, 0); + } + public IP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.IP, 0); + } + public NUM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NUM, 0); + } + public KEEPEMPTY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.KEEPEMPTY, 0); + } + public CONSECUTIVE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CONSECUTIVE, 0); + } + public DEDUP_SPLITVALUES(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DEDUP_SPLITVALUES, 0); + } + public PARTITIONS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PARTITIONS, 0); + } + public ALLNUM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ALLNUM, 0); + } + public DELIM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DELIM, 0); + } + public CENTROIDS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CENTROIDS, 0); + } + public ITERATIONS(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ITERATIONS, 0); + } + public DISTANCE_TYPE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DISTANCE_TYPE, 0); + } + public NUMBER_OF_TREES(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.NUMBER_OF_TREES, 0); + } + public SHINGLE_SIZE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SHINGLE_SIZE, 0); + } + public SAMPLE_SIZE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SAMPLE_SIZE, 0); + } + public OUTPUT_AFTER(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.OUTPUT_AFTER, 0); + } + public TIME_DECAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_DECAY, 0); + } + public ANOMALY_RATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ANOMALY_RATE, 0); + } + public CATEGORY_FIELD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.CATEGORY_FIELD, 0); + } + public TIME_FIELD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_FIELD, 0); + } + public TIME_ZONE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TIME_ZONE, 0); + } + public TRAINING_DATA_SIZE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TRAINING_DATA_SIZE, 0); + } + public ANOMALY_SCORE_THRESHOLD(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ANOMALY_SCORE_THRESHOLD, 0); + } + public AVG(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.AVG, 0); + } + public COUNT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.COUNT, 0); + } + public DISTINCT_COUNT(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DISTINCT_COUNT, 0); + } + public ESTDC(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ESTDC, 0); + } + public ESTDC_ERROR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.ESTDC_ERROR, 0); + } + public MAX(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MAX, 0); + } + public MEAN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MEAN, 0); + } + public MEDIAN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MEDIAN, 0); + } + public MIN(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MIN, 0); + } + public MODE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.MODE, 0); + } + public RANGE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RANGE, 0); + } + public STDEV(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STDEV, 0); + } + public STDEVP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STDEVP, 0); + } + public SUM(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SUM, 0); + } + public SUMSQ(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SUMSQ, 0); + } + public VAR_SAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.VAR_SAMP, 0); + } + public VAR_POP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.VAR_POP, 0); + } + public STDDEV_SAMP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STDDEV_SAMP, 0); + } + public STDDEV_POP(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.STDDEV_POP, 0); + } + public PERCENTILE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PERCENTILE, 0); + } + public TAKE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.TAKE, 0); + } + public FIRST(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.FIRST, 0); + } + public LAST(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LAST, 0); + } + public LIST(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LIST, 0); + } + public VALUES(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.VALUES, 0); + } + public EARLIEST(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EARLIEST, 0); + } + public EARLIEST_TIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.EARLIEST_TIME, 0); + } + public LATEST(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LATEST, 0); + } + public LATEST_TIME(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.LATEST_TIME, 0); + } + public PER_DAY(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PER_DAY, 0); + } + public PER_HOUR(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PER_HOUR, 0); + } + public PER_MINUTE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PER_MINUTE, 0); + } + public PER_SECOND(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.PER_SECOND, 0); + } + public RATE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.RATE, 0); + } + public SPARKLINE(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.SPARKLINE, 0); + } + public C(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.C, 0); + } + public DC(): antlr.TerminalNode | null { + return this.getToken(OpenSearchPPLParser.DC, 0); + } + public override get ruleIndex(): number { + return OpenSearchPPLParser.RULE_keywordsCanBeId; + } + public override accept(visitor: OpenSearchPPLParserVisitor): Result | null { + if (visitor.visitKeywordsCanBeId) { + return visitor.visitKeywordsCanBeId(this); + } else { + return visitor.visitChildren(this); + } + } +} diff --git a/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParserVisitor.ts b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParserVisitor.ts new file mode 100644 index 000000000000..9ddb17bd038d --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/.generated/OpenSearchPPLParserVisitor.ts @@ -0,0 +1,975 @@ +// Generated from ./src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLParser.g4 by ANTLR 4.13.1 + +import { AbstractParseTreeVisitor } from "antlr4ng"; + + +import { RootContext } from "./OpenSearchPPLParser.js"; +import { PplStatementContext } from "./OpenSearchPPLParser.js"; +import { DmlStatementContext } from "./OpenSearchPPLParser.js"; +import { QueryStatementContext } from "./OpenSearchPPLParser.js"; +import { PplCommandsContext } from "./OpenSearchPPLParser.js"; +import { CommandsContext } from "./OpenSearchPPLParser.js"; +import { SearchFromContext } from "./OpenSearchPPLParser.js"; +import { SearchFromFilterContext } from "./OpenSearchPPLParser.js"; +import { SearchFilterFromContext } from "./OpenSearchPPLParser.js"; +import { DescribeCommandContext } from "./OpenSearchPPLParser.js"; +import { ShowDataSourcesCommandContext } from "./OpenSearchPPLParser.js"; +import { WhereCommandContext } from "./OpenSearchPPLParser.js"; +import { FieldsCommandContext } from "./OpenSearchPPLParser.js"; +import { RenameCommandContext } from "./OpenSearchPPLParser.js"; +import { StatsCommandContext } from "./OpenSearchPPLParser.js"; +import { DedupCommandContext } from "./OpenSearchPPLParser.js"; +import { SortCommandContext } from "./OpenSearchPPLParser.js"; +import { EvalCommandContext } from "./OpenSearchPPLParser.js"; +import { HeadCommandContext } from "./OpenSearchPPLParser.js"; +import { TopCommandContext } from "./OpenSearchPPLParser.js"; +import { RareCommandContext } from "./OpenSearchPPLParser.js"; +import { GrokCommandContext } from "./OpenSearchPPLParser.js"; +import { ParseCommandContext } from "./OpenSearchPPLParser.js"; +import { PatternsCommandContext } from "./OpenSearchPPLParser.js"; +import { PatternsParameterContext } from "./OpenSearchPPLParser.js"; +import { PatternsMethodContext } from "./OpenSearchPPLParser.js"; +import { KmeansCommandContext } from "./OpenSearchPPLParser.js"; +import { KmeansParameterContext } from "./OpenSearchPPLParser.js"; +import { AdCommandContext } from "./OpenSearchPPLParser.js"; +import { AdParameterContext } from "./OpenSearchPPLParser.js"; +import { MlCommandContext } from "./OpenSearchPPLParser.js"; +import { MlArgContext } from "./OpenSearchPPLParser.js"; +import { FromClauseContext } from "./OpenSearchPPLParser.js"; +import { TableSourceClauseContext } from "./OpenSearchPPLParser.js"; +import { RenameClasueContext } from "./OpenSearchPPLParser.js"; +import { ByClauseContext } from "./OpenSearchPPLParser.js"; +import { StatsByClauseContext } from "./OpenSearchPPLParser.js"; +import { BySpanClauseContext } from "./OpenSearchPPLParser.js"; +import { SpanClauseContext } from "./OpenSearchPPLParser.js"; +import { SortbyClauseContext } from "./OpenSearchPPLParser.js"; +import { EvalClauseContext } from "./OpenSearchPPLParser.js"; +import { StatsAggTermContext } from "./OpenSearchPPLParser.js"; +import { StatsFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { CountAllFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { DistinctCountFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { PercentileAggFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { TakeAggFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { StatsFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { TakeAggFunctionContext } from "./OpenSearchPPLParser.js"; +import { PercentileAggFunctionContext } from "./OpenSearchPPLParser.js"; +import { ExpressionContext } from "./OpenSearchPPLParser.js"; +import { RelevanceExprContext } from "./OpenSearchPPLParser.js"; +import { LogicalNotContext } from "./OpenSearchPPLParser.js"; +import { BooleanExprContext } from "./OpenSearchPPLParser.js"; +import { LogicalAndContext } from "./OpenSearchPPLParser.js"; +import { ComparsionContext } from "./OpenSearchPPLParser.js"; +import { LogicalXorContext } from "./OpenSearchPPLParser.js"; +import { LogicalOrContext } from "./OpenSearchPPLParser.js"; +import { CompareExprContext } from "./OpenSearchPPLParser.js"; +import { InExprContext } from "./OpenSearchPPLParser.js"; +import { PositionFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { ValueExpressionDefaultContext } from "./OpenSearchPPLParser.js"; +import { ParentheticValueExprContext } from "./OpenSearchPPLParser.js"; +import { GetFormatFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { ExtractFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { BinaryArithmeticContext } from "./OpenSearchPPLParser.js"; +import { TimestampFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { PrimaryExpressionContext } from "./OpenSearchPPLParser.js"; +import { PositionFunctionContext } from "./OpenSearchPPLParser.js"; +import { BooleanExpressionContext } from "./OpenSearchPPLParser.js"; +import { RelevanceExpressionContext } from "./OpenSearchPPLParser.js"; +import { SingleFieldRelevanceFunctionContext } from "./OpenSearchPPLParser.js"; +import { MultiFieldRelevanceFunctionContext } from "./OpenSearchPPLParser.js"; +import { TableSourceContext } from "./OpenSearchPPLParser.js"; +import { TableFunctionContext } from "./OpenSearchPPLParser.js"; +import { FieldListContext } from "./OpenSearchPPLParser.js"; +import { WcFieldListContext } from "./OpenSearchPPLParser.js"; +import { SortFieldContext } from "./OpenSearchPPLParser.js"; +import { SortFieldExpressionContext } from "./OpenSearchPPLParser.js"; +import { FieldExpressionContext } from "./OpenSearchPPLParser.js"; +import { WcFieldExpressionContext } from "./OpenSearchPPLParser.js"; +import { EvalFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { DataTypeFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { BooleanFunctionCallContext } from "./OpenSearchPPLParser.js"; +import { ConvertedDataTypeContext } from "./OpenSearchPPLParser.js"; +import { EvalFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { FunctionArgsContext } from "./OpenSearchPPLParser.js"; +import { FunctionArgContext } from "./OpenSearchPPLParser.js"; +import { RelevanceArgContext } from "./OpenSearchPPLParser.js"; +import { RelevanceArgNameContext } from "./OpenSearchPPLParser.js"; +import { RelevanceFieldAndWeightContext } from "./OpenSearchPPLParser.js"; +import { RelevanceFieldWeightContext } from "./OpenSearchPPLParser.js"; +import { RelevanceFieldContext } from "./OpenSearchPPLParser.js"; +import { RelevanceQueryContext } from "./OpenSearchPPLParser.js"; +import { RelevanceArgValueContext } from "./OpenSearchPPLParser.js"; +import { MathematicalFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { TrigonometricFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { DateTimeFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { GetFormatFunctionContext } from "./OpenSearchPPLParser.js"; +import { GetFormatTypeContext } from "./OpenSearchPPLParser.js"; +import { ExtractFunctionContext } from "./OpenSearchPPLParser.js"; +import { SimpleDateTimePartContext } from "./OpenSearchPPLParser.js"; +import { ComplexDateTimePartContext } from "./OpenSearchPPLParser.js"; +import { DatetimePartContext } from "./OpenSearchPPLParser.js"; +import { TimestampFunctionContext } from "./OpenSearchPPLParser.js"; +import { TimestampFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { ConditionFunctionBaseContext } from "./OpenSearchPPLParser.js"; +import { SystemFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { TextFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { PositionFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { ComparisonOperatorContext } from "./OpenSearchPPLParser.js"; +import { SingleFieldRelevanceFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { MultiFieldRelevanceFunctionNameContext } from "./OpenSearchPPLParser.js"; +import { LiteralValueContext } from "./OpenSearchPPLParser.js"; +import { IntervalLiteralContext } from "./OpenSearchPPLParser.js"; +import { StringLiteralContext } from "./OpenSearchPPLParser.js"; +import { IntegerLiteralContext } from "./OpenSearchPPLParser.js"; +import { DecimalLiteralContext } from "./OpenSearchPPLParser.js"; +import { BooleanLiteralContext } from "./OpenSearchPPLParser.js"; +import { DatetimeLiteralContext } from "./OpenSearchPPLParser.js"; +import { DateLiteralContext } from "./OpenSearchPPLParser.js"; +import { TimeLiteralContext } from "./OpenSearchPPLParser.js"; +import { TimestampLiteralContext } from "./OpenSearchPPLParser.js"; +import { IntervalUnitContext } from "./OpenSearchPPLParser.js"; +import { TimespanUnitContext } from "./OpenSearchPPLParser.js"; +import { ValueListContext } from "./OpenSearchPPLParser.js"; +import { IdentsAsQualifiedNameContext } from "./OpenSearchPPLParser.js"; +import { IdentsAsTableQualifiedNameContext } from "./OpenSearchPPLParser.js"; +import { IdentsAsWildcardQualifiedNameContext } from "./OpenSearchPPLParser.js"; +import { IdentContext } from "./OpenSearchPPLParser.js"; +import { TableIdentContext } from "./OpenSearchPPLParser.js"; +import { WildcardContext } from "./OpenSearchPPLParser.js"; +import { KeywordsCanBeIdContext } from "./OpenSearchPPLParser.js"; + + +/** + * This interface defines a complete generic visitor for a parse tree produced + * by `OpenSearchPPLParser`. + * + * @param The return type of the visit operation. Use `void` for + * operations with no return type. + */ +export class OpenSearchPPLParserVisitor extends AbstractParseTreeVisitor { + /** + * Visit a parse tree produced by `OpenSearchPPLParser.root`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRoot?: (ctx: RootContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.pplStatement`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPplStatement?: (ctx: PplStatementContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.dmlStatement`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDmlStatement?: (ctx: DmlStatementContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.queryStatement`. + * @param ctx the parse tree + * @return the visitor result + */ + visitQueryStatement?: (ctx: QueryStatementContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.pplCommands`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPplCommands?: (ctx: PplCommandsContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.commands`. + * @param ctx the parse tree + * @return the visitor result + */ + visitCommands?: (ctx: CommandsContext) => Result; + /** + * Visit a parse tree produced by the `searchFrom` + * labeled alternative in `OpenSearchPPLParser.searchCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSearchFrom?: (ctx: SearchFromContext) => Result; + /** + * Visit a parse tree produced by the `searchFromFilter` + * labeled alternative in `OpenSearchPPLParser.searchCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSearchFromFilter?: (ctx: SearchFromFilterContext) => Result; + /** + * Visit a parse tree produced by the `searchFilterFrom` + * labeled alternative in `OpenSearchPPLParser.searchCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSearchFilterFrom?: (ctx: SearchFilterFromContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.describeCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDescribeCommand?: (ctx: DescribeCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.showDataSourcesCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitShowDataSourcesCommand?: (ctx: ShowDataSourcesCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.whereCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitWhereCommand?: (ctx: WhereCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.fieldsCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitFieldsCommand?: (ctx: FieldsCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.renameCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRenameCommand?: (ctx: RenameCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.statsCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitStatsCommand?: (ctx: StatsCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.dedupCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDedupCommand?: (ctx: DedupCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.sortCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSortCommand?: (ctx: SortCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.evalCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitEvalCommand?: (ctx: EvalCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.headCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitHeadCommand?: (ctx: HeadCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.topCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTopCommand?: (ctx: TopCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.rareCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRareCommand?: (ctx: RareCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.grokCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitGrokCommand?: (ctx: GrokCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.parseCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitParseCommand?: (ctx: ParseCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.patternsCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPatternsCommand?: (ctx: PatternsCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.patternsParameter`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPatternsParameter?: (ctx: PatternsParameterContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.patternsMethod`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPatternsMethod?: (ctx: PatternsMethodContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.kmeansCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitKmeansCommand?: (ctx: KmeansCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.kmeansParameter`. + * @param ctx the parse tree + * @return the visitor result + */ + visitKmeansParameter?: (ctx: KmeansParameterContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.adCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitAdCommand?: (ctx: AdCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.adParameter`. + * @param ctx the parse tree + * @return the visitor result + */ + visitAdParameter?: (ctx: AdParameterContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.mlCommand`. + * @param ctx the parse tree + * @return the visitor result + */ + visitMlCommand?: (ctx: MlCommandContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.mlArg`. + * @param ctx the parse tree + * @return the visitor result + */ + visitMlArg?: (ctx: MlArgContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.fromClause`. + * @param ctx the parse tree + * @return the visitor result + */ + visitFromClause?: (ctx: FromClauseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.tableSourceClause`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTableSourceClause?: (ctx: TableSourceClauseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.renameClasue`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRenameClasue?: (ctx: RenameClasueContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.byClause`. + * @param ctx the parse tree + * @return the visitor result + */ + visitByClause?: (ctx: ByClauseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.statsByClause`. + * @param ctx the parse tree + * @return the visitor result + */ + visitStatsByClause?: (ctx: StatsByClauseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.bySpanClause`. + * @param ctx the parse tree + * @return the visitor result + */ + visitBySpanClause?: (ctx: BySpanClauseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.spanClause`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSpanClause?: (ctx: SpanClauseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.sortbyClause`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSortbyClause?: (ctx: SortbyClauseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.evalClause`. + * @param ctx the parse tree + * @return the visitor result + */ + visitEvalClause?: (ctx: EvalClauseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.statsAggTerm`. + * @param ctx the parse tree + * @return the visitor result + */ + visitStatsAggTerm?: (ctx: StatsAggTermContext) => Result; + /** + * Visit a parse tree produced by the `statsFunctionCall` + * labeled alternative in `OpenSearchPPLParser.statsFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitStatsFunctionCall?: (ctx: StatsFunctionCallContext) => Result; + /** + * Visit a parse tree produced by the `countAllFunctionCall` + * labeled alternative in `OpenSearchPPLParser.statsFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitCountAllFunctionCall?: (ctx: CountAllFunctionCallContext) => Result; + /** + * Visit a parse tree produced by the `distinctCountFunctionCall` + * labeled alternative in `OpenSearchPPLParser.statsFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDistinctCountFunctionCall?: (ctx: DistinctCountFunctionCallContext) => Result; + /** + * Visit a parse tree produced by the `percentileAggFunctionCall` + * labeled alternative in `OpenSearchPPLParser.statsFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPercentileAggFunctionCall?: (ctx: PercentileAggFunctionCallContext) => Result; + /** + * Visit a parse tree produced by the `takeAggFunctionCall` + * labeled alternative in `OpenSearchPPLParser.statsFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTakeAggFunctionCall?: (ctx: TakeAggFunctionCallContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.statsFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitStatsFunctionName?: (ctx: StatsFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.takeAggFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTakeAggFunction?: (ctx: TakeAggFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.percentileAggFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPercentileAggFunction?: (ctx: PercentileAggFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.expression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitExpression?: (ctx: ExpressionContext) => Result; + /** + * Visit a parse tree produced by the `relevanceExpr` + * labeled alternative in `OpenSearchPPLParser.logicalExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceExpr?: (ctx: RelevanceExprContext) => Result; + /** + * Visit a parse tree produced by the `logicalNot` + * labeled alternative in `OpenSearchPPLParser.logicalExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitLogicalNot?: (ctx: LogicalNotContext) => Result; + /** + * Visit a parse tree produced by the `booleanExpr` + * labeled alternative in `OpenSearchPPLParser.logicalExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitBooleanExpr?: (ctx: BooleanExprContext) => Result; + /** + * Visit a parse tree produced by the `logicalAnd` + * labeled alternative in `OpenSearchPPLParser.logicalExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitLogicalAnd?: (ctx: LogicalAndContext) => Result; + /** + * Visit a parse tree produced by the `comparsion` + * labeled alternative in `OpenSearchPPLParser.logicalExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitComparsion?: (ctx: ComparsionContext) => Result; + /** + * Visit a parse tree produced by the `logicalXor` + * labeled alternative in `OpenSearchPPLParser.logicalExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitLogicalXor?: (ctx: LogicalXorContext) => Result; + /** + * Visit a parse tree produced by the `logicalOr` + * labeled alternative in `OpenSearchPPLParser.logicalExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitLogicalOr?: (ctx: LogicalOrContext) => Result; + /** + * Visit a parse tree produced by the `compareExpr` + * labeled alternative in `OpenSearchPPLParser.comparisonExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitCompareExpr?: (ctx: CompareExprContext) => Result; + /** + * Visit a parse tree produced by the `inExpr` + * labeled alternative in `OpenSearchPPLParser.comparisonExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitInExpr?: (ctx: InExprContext) => Result; + /** + * Visit a parse tree produced by the `positionFunctionCall` + * labeled alternative in `OpenSearchPPLParser.valueExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPositionFunctionCall?: (ctx: PositionFunctionCallContext) => Result; + /** + * Visit a parse tree produced by the `valueExpressionDefault` + * labeled alternative in `OpenSearchPPLParser.valueExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitValueExpressionDefault?: (ctx: ValueExpressionDefaultContext) => Result; + /** + * Visit a parse tree produced by the `parentheticValueExpr` + * labeled alternative in `OpenSearchPPLParser.valueExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitParentheticValueExpr?: (ctx: ParentheticValueExprContext) => Result; + /** + * Visit a parse tree produced by the `getFormatFunctionCall` + * labeled alternative in `OpenSearchPPLParser.valueExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitGetFormatFunctionCall?: (ctx: GetFormatFunctionCallContext) => Result; + /** + * Visit a parse tree produced by the `extractFunctionCall` + * labeled alternative in `OpenSearchPPLParser.valueExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitExtractFunctionCall?: (ctx: ExtractFunctionCallContext) => Result; + /** + * Visit a parse tree produced by the `binaryArithmetic` + * labeled alternative in `OpenSearchPPLParser.valueExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitBinaryArithmetic?: (ctx: BinaryArithmeticContext) => Result; + /** + * Visit a parse tree produced by the `timestampFunctionCall` + * labeled alternative in `OpenSearchPPLParser.valueExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTimestampFunctionCall?: (ctx: TimestampFunctionCallContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.primaryExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPrimaryExpression?: (ctx: PrimaryExpressionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.positionFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPositionFunction?: (ctx: PositionFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.booleanExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitBooleanExpression?: (ctx: BooleanExpressionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.relevanceExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceExpression?: (ctx: RelevanceExpressionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.singleFieldRelevanceFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSingleFieldRelevanceFunction?: (ctx: SingleFieldRelevanceFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.multiFieldRelevanceFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitMultiFieldRelevanceFunction?: (ctx: MultiFieldRelevanceFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.tableSource`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTableSource?: (ctx: TableSourceContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.tableFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTableFunction?: (ctx: TableFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.fieldList`. + * @param ctx the parse tree + * @return the visitor result + */ + visitFieldList?: (ctx: FieldListContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.wcFieldList`. + * @param ctx the parse tree + * @return the visitor result + */ + visitWcFieldList?: (ctx: WcFieldListContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.sortField`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSortField?: (ctx: SortFieldContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.sortFieldExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSortFieldExpression?: (ctx: SortFieldExpressionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.fieldExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitFieldExpression?: (ctx: FieldExpressionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.wcFieldExpression`. + * @param ctx the parse tree + * @return the visitor result + */ + visitWcFieldExpression?: (ctx: WcFieldExpressionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.evalFunctionCall`. + * @param ctx the parse tree + * @return the visitor result + */ + visitEvalFunctionCall?: (ctx: EvalFunctionCallContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.dataTypeFunctionCall`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDataTypeFunctionCall?: (ctx: DataTypeFunctionCallContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.booleanFunctionCall`. + * @param ctx the parse tree + * @return the visitor result + */ + visitBooleanFunctionCall?: (ctx: BooleanFunctionCallContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.convertedDataType`. + * @param ctx the parse tree + * @return the visitor result + */ + visitConvertedDataType?: (ctx: ConvertedDataTypeContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.evalFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitEvalFunctionName?: (ctx: EvalFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.functionArgs`. + * @param ctx the parse tree + * @return the visitor result + */ + visitFunctionArgs?: (ctx: FunctionArgsContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.functionArg`. + * @param ctx the parse tree + * @return the visitor result + */ + visitFunctionArg?: (ctx: FunctionArgContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.relevanceArg`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceArg?: (ctx: RelevanceArgContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.relevanceArgName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceArgName?: (ctx: RelevanceArgNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.relevanceFieldAndWeight`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceFieldAndWeight?: (ctx: RelevanceFieldAndWeightContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.relevanceFieldWeight`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceFieldWeight?: (ctx: RelevanceFieldWeightContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.relevanceField`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceField?: (ctx: RelevanceFieldContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.relevanceQuery`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceQuery?: (ctx: RelevanceQueryContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.relevanceArgValue`. + * @param ctx the parse tree + * @return the visitor result + */ + visitRelevanceArgValue?: (ctx: RelevanceArgValueContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.mathematicalFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitMathematicalFunctionName?: (ctx: MathematicalFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.trigonometricFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTrigonometricFunctionName?: (ctx: TrigonometricFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.dateTimeFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDateTimeFunctionName?: (ctx: DateTimeFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.getFormatFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitGetFormatFunction?: (ctx: GetFormatFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.getFormatType`. + * @param ctx the parse tree + * @return the visitor result + */ + visitGetFormatType?: (ctx: GetFormatTypeContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.extractFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitExtractFunction?: (ctx: ExtractFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.simpleDateTimePart`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSimpleDateTimePart?: (ctx: SimpleDateTimePartContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.complexDateTimePart`. + * @param ctx the parse tree + * @return the visitor result + */ + visitComplexDateTimePart?: (ctx: ComplexDateTimePartContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.datetimePart`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDatetimePart?: (ctx: DatetimePartContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.timestampFunction`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTimestampFunction?: (ctx: TimestampFunctionContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.timestampFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTimestampFunctionName?: (ctx: TimestampFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.conditionFunctionBase`. + * @param ctx the parse tree + * @return the visitor result + */ + visitConditionFunctionBase?: (ctx: ConditionFunctionBaseContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.systemFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSystemFunctionName?: (ctx: SystemFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.textFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTextFunctionName?: (ctx: TextFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.positionFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitPositionFunctionName?: (ctx: PositionFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.comparisonOperator`. + * @param ctx the parse tree + * @return the visitor result + */ + visitComparisonOperator?: (ctx: ComparisonOperatorContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.singleFieldRelevanceFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitSingleFieldRelevanceFunctionName?: (ctx: SingleFieldRelevanceFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.multiFieldRelevanceFunctionName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitMultiFieldRelevanceFunctionName?: (ctx: MultiFieldRelevanceFunctionNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.literalValue`. + * @param ctx the parse tree + * @return the visitor result + */ + visitLiteralValue?: (ctx: LiteralValueContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.intervalLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitIntervalLiteral?: (ctx: IntervalLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.stringLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitStringLiteral?: (ctx: StringLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.integerLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitIntegerLiteral?: (ctx: IntegerLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.decimalLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDecimalLiteral?: (ctx: DecimalLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.booleanLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitBooleanLiteral?: (ctx: BooleanLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.datetimeLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDatetimeLiteral?: (ctx: DatetimeLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.dateLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitDateLiteral?: (ctx: DateLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.timeLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTimeLiteral?: (ctx: TimeLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.timestampLiteral`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTimestampLiteral?: (ctx: TimestampLiteralContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.intervalUnit`. + * @param ctx the parse tree + * @return the visitor result + */ + visitIntervalUnit?: (ctx: IntervalUnitContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.timespanUnit`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTimespanUnit?: (ctx: TimespanUnitContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.valueList`. + * @param ctx the parse tree + * @return the visitor result + */ + visitValueList?: (ctx: ValueListContext) => Result; + /** + * Visit a parse tree produced by the `identsAsQualifiedName` + * labeled alternative in `OpenSearchPPLParser.qualifiedName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitIdentsAsQualifiedName?: (ctx: IdentsAsQualifiedNameContext) => Result; + /** + * Visit a parse tree produced by the `identsAsTableQualifiedName` + * labeled alternative in `OpenSearchPPLParser.tableQualifiedName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitIdentsAsTableQualifiedName?: (ctx: IdentsAsTableQualifiedNameContext) => Result; + /** + * Visit a parse tree produced by the `identsAsWildcardQualifiedName` + * labeled alternative in `OpenSearchPPLParser.wcQualifiedName`. + * @param ctx the parse tree + * @return the visitor result + */ + visitIdentsAsWildcardQualifiedName?: (ctx: IdentsAsWildcardQualifiedNameContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.ident`. + * @param ctx the parse tree + * @return the visitor result + */ + visitIdent?: (ctx: IdentContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.tableIdent`. + * @param ctx the parse tree + * @return the visitor result + */ + visitTableIdent?: (ctx: TableIdentContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.wildcard`. + * @param ctx the parse tree + * @return the visitor result + */ + visitWildcard?: (ctx: WildcardContext) => Result; + /** + * Visit a parse tree produced by `OpenSearchPPLParser.keywordsCanBeId`. + * @param ctx the parse tree + * @return the visitor result + */ + visitKeywordsCanBeId?: (ctx: KeywordsCanBeIdContext) => Result; +} + diff --git a/src/plugins/data/public/antlr/opensearch_ppl/code_completion.ts b/src/plugins/data/public/antlr/opensearch_ppl/code_completion.ts new file mode 100644 index 000000000000..9ca2cf4f40fe --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/code_completion.ts @@ -0,0 +1,72 @@ +/* + * 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. + */ + +import { monaco } from '@osd/monaco'; +import { CursorPosition, AutocompleteResultBase } from '../shared/types'; +import { fetchFieldSuggestions, parseQuery } from '../shared/utils'; +import { openSearchPplAutocompleteData } from './opensearch_ppl_autocomplete'; +import { QuerySuggestion, QuerySuggestionGetFnArgs } from '../../autocomplete'; +import { SuggestionItemDetailsTags } from '../shared/constants'; + +export const getSuggestions = async ({ + selectionStart, + selectionEnd, + indexPattern, + position, + query, + services, +}: QuerySuggestionGetFnArgs) => { + if (!services || !services.appName || !indexPattern) return []; + try { + const { lineNumber, column } = position || {}; + const suggestions = getOpenSearchPplAutoCompleteSuggestions(query, { + line: lineNumber || selectionStart, + column: column || selectionEnd, + }); + + const finalSuggestions: QuerySuggestion[] = []; + + if (suggestions.suggestColumns) { + finalSuggestions.push(...fetchFieldSuggestions(indexPattern)); + } + + // Fill in PPL keywords + if (suggestions.suggestKeywords?.length) { + finalSuggestions.push( + ...suggestions.suggestKeywords.map((sk) => ({ + text: sk.value, + type: monaco.languages.CompletionItemKind.Keyword, + detail: SuggestionItemDetailsTags.Keyword, + })) + ); + } + return finalSuggestions; + } catch (e) { + return []; + } +}; + +export const getOpenSearchPplAutoCompleteSuggestions = ( + query: string, + cursor: CursorPosition +): AutocompleteResultBase => { + return parseQuery({ + Lexer: openSearchPplAutocompleteData.Lexer, + Parser: openSearchPplAutocompleteData.Parser, + tokenDictionary: openSearchPplAutocompleteData.tokenDictionary, + ignoredTokens: openSearchPplAutocompleteData.ignoredTokens, + rulesToVisit: openSearchPplAutocompleteData.rulesToVisit, + getParseTree: openSearchPplAutocompleteData.getParseTree, + enrichAutocompleteResult: openSearchPplAutocompleteData.enrichAutocompleteResult, + query, + cursor, + }); +}; diff --git a/src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLLexer.g4 b/src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLLexer.g4 new file mode 100644 index 000000000000..1e08b9c61f1a --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLLexer.g4 @@ -0,0 +1,406 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + + +lexer grammar OpenSearchPPLLexer; + +channels { WHITESPACE, ERRORCHANNEL } + +options { + caseInsensitive = true; +} + +SPACE: [ \t\r\n]+ -> channel(HIDDEN); + + +// COMMAND KEYWORDS +SEARCH: 'SEARCH'; +DESCRIBE: 'DESCRIBE'; +SHOW: 'SHOW'; +FROM: 'FROM'; +WHERE: 'WHERE'; +FIELDS: 'FIELDS'; +RENAME: 'RENAME'; +STATS: 'STATS'; +DEDUP: 'DEDUP'; +SORT: 'SORT'; +EVAL: 'EVAL'; +HEAD: 'HEAD'; +TOP: 'TOP'; +RARE: 'RARE'; +PARSE: 'PARSE'; +METHOD: 'METHOD'; +REGEX: 'REGEX'; +PUNCT: 'PUNCT'; +GROK: 'GROK'; +PATTERN: 'PATTERN'; +PATTERNS: 'PATTERNS'; +NEW_FIELD: 'NEW_FIELD'; +KMEANS: 'KMEANS'; +AD: 'AD'; +ML: 'ML'; + +// COMMAND ASSIST KEYWORDS +AS: 'AS'; +BY: 'BY'; +SOURCE: 'SOURCE'; +INDEX: 'INDEX'; +D: 'D'; +DESC: 'DESC'; +DATASOURCES: 'DATASOURCES'; + +// CLAUSE KEYWORDS +SORTBY: 'SORTBY'; + +// FIELD KEYWORDS +AUTO: 'AUTO'; +STR: 'STR'; +IP: 'IP'; +NUM: 'NUM'; + +// ARGUMENT KEYWORDS +KEEPEMPTY: 'KEEPEMPTY'; +CONSECUTIVE: 'CONSECUTIVE'; +DEDUP_SPLITVALUES: 'DEDUP_SPLITVALUES'; +PARTITIONS: 'PARTITIONS'; +ALLNUM: 'ALLNUM'; +DELIM: 'DELIM'; +CENTROIDS: 'CENTROIDS'; +ITERATIONS: 'ITERATIONS'; +DISTANCE_TYPE: 'DISTANCE_TYPE'; +NUMBER_OF_TREES: 'NUMBER_OF_TREES'; +SHINGLE_SIZE: 'SHINGLE_SIZE'; +SAMPLE_SIZE: 'SAMPLE_SIZE'; +OUTPUT_AFTER: 'OUTPUT_AFTER'; +TIME_DECAY: 'TIME_DECAY'; +ANOMALY_RATE: 'ANOMALY_RATE'; +CATEGORY_FIELD: 'CATEGORY_FIELD'; +TIME_FIELD: 'TIME_FIELD'; +TIME_ZONE: 'TIME_ZONE'; +TRAINING_DATA_SIZE: 'TRAINING_DATA_SIZE'; +ANOMALY_SCORE_THRESHOLD: 'ANOMALY_SCORE_THRESHOLD'; + +// COMPARISON FUNCTION KEYWORDS +CASE: 'CASE'; +IN: 'IN'; + +// LOGICAL KEYWORDS +NOT: 'NOT'; +OR: 'OR'; +AND: 'AND'; +XOR: 'XOR'; +TRUE: 'TRUE'; +FALSE: 'FALSE'; +REGEXP: 'REGEXP'; + +// DATETIME, INTERVAL AND UNIT KEYWORDS +CONVERT_TZ: 'CONVERT_TZ'; +DATETIME: 'DATETIME'; +DAY: 'DAY'; +DAY_HOUR: 'DAY_HOUR'; +DAY_MICROSECOND: 'DAY_MICROSECOND'; +DAY_MINUTE: 'DAY_MINUTE'; +DAY_OF_YEAR: 'DAY_OF_YEAR'; +DAY_SECOND: 'DAY_SECOND'; +HOUR: 'HOUR'; +HOUR_MICROSECOND: 'HOUR_MICROSECOND'; +HOUR_MINUTE: 'HOUR_MINUTE'; +HOUR_OF_DAY: 'HOUR_OF_DAY'; +HOUR_SECOND: 'HOUR_SECOND'; +INTERVAL: 'INTERVAL'; +MICROSECOND: 'MICROSECOND'; +MILLISECOND: 'MILLISECOND'; +MINUTE: 'MINUTE'; +MINUTE_MICROSECOND: 'MINUTE_MICROSECOND'; +MINUTE_OF_DAY: 'MINUTE_OF_DAY'; +MINUTE_OF_HOUR: 'MINUTE_OF_HOUR'; +MINUTE_SECOND: 'MINUTE_SECOND'; +MONTH: 'MONTH'; +MONTH_OF_YEAR: 'MONTH_OF_YEAR'; +QUARTER: 'QUARTER'; +SECOND: 'SECOND'; +SECOND_MICROSECOND: 'SECOND_MICROSECOND'; +SECOND_OF_MINUTE: 'SECOND_OF_MINUTE'; +WEEK: 'WEEK'; +WEEK_OF_YEAR: 'WEEK_OF_YEAR'; +YEAR: 'YEAR'; +YEAR_MONTH: 'YEAR_MONTH'; + +// DATASET TYPES +DATAMODEL: 'DATAMODEL'; +LOOKUP: 'LOOKUP'; +SAVEDSEARCH: 'SAVEDSEARCH'; + +// CONVERTED DATA TYPES +INT: 'INT'; +INTEGER: 'INTEGER'; +DOUBLE: 'DOUBLE'; +LONG: 'LONG'; +FLOAT: 'FLOAT'; +STRING: 'STRING'; +BOOLEAN: 'BOOLEAN'; + +// SPECIAL CHARACTERS AND OPERATORS +PIPE: '|'; +COMMA: ','; +DOT: '.'; +EQUAL: '='; +GREATER: '>'; +LESS: '<'; +NOT_GREATER: '<' '='; +NOT_LESS: '>' '='; +NOT_EQUAL: '!' '='; +PLUS: '+'; +MINUS: '-'; +STAR: '*'; +DIVIDE: '/'; +MODULE: '%'; +EXCLAMATION_SYMBOL: '!'; +COLON: ':'; +LT_PRTHS: '('; +RT_PRTHS: ')'; +LT_SQR_PRTHS: '['; +RT_SQR_PRTHS: ']'; +SINGLE_QUOTE: '\''; +DOUBLE_QUOTE: '"'; +BACKTICK: '`'; + +// Operators. Bit + +BIT_NOT_OP: '~'; +BIT_AND_OP: '&'; +BIT_XOR_OP: '^'; + +// AGGREGATIONS +AVG: 'AVG'; +COUNT: 'COUNT'; +DISTINCT_COUNT: 'DISTINCT_COUNT'; +ESTDC: 'ESTDC'; +ESTDC_ERROR: 'ESTDC_ERROR'; +MAX: 'MAX'; +MEAN: 'MEAN'; +MEDIAN: 'MEDIAN'; +MIN: 'MIN'; +MODE: 'MODE'; +RANGE: 'RANGE'; +STDEV: 'STDEV'; +STDEVP: 'STDEVP'; +SUM: 'SUM'; +SUMSQ: 'SUMSQ'; +VAR_SAMP: 'VAR_SAMP'; +VAR_POP: 'VAR_POP'; +STDDEV_SAMP: 'STDDEV_SAMP'; +STDDEV_POP: 'STDDEV_POP'; +PERCENTILE: 'PERCENTILE'; +TAKE: 'TAKE'; +FIRST: 'FIRST'; +LAST: 'LAST'; +LIST: 'LIST'; +VALUES: 'VALUES'; +EARLIEST: 'EARLIEST'; +EARLIEST_TIME: 'EARLIEST_TIME'; +LATEST: 'LATEST'; +LATEST_TIME: 'LATEST_TIME'; +PER_DAY: 'PER_DAY'; +PER_HOUR: 'PER_HOUR'; +PER_MINUTE: 'PER_MINUTE'; +PER_SECOND: 'PER_SECOND'; +RATE: 'RATE'; +SPARKLINE: 'SPARKLINE'; +C: 'C'; +DC: 'DC'; + +// BASIC FUNCTIONS +ABS: 'ABS'; +CBRT: 'CBRT'; +CEIL: 'CEIL'; +CEILING: 'CEILING'; +CONV: 'CONV'; +CRC32: 'CRC32'; +E: 'E'; +EXP: 'EXP'; +FLOOR: 'FLOOR'; +LN: 'LN'; +LOG: 'LOG'; +LOG10: 'LOG10'; +LOG2: 'LOG2'; +MOD: 'MOD'; +PI: 'PI'; +POSITION: 'POSITION'; +POW: 'POW'; +POWER: 'POWER'; +RAND: 'RAND'; +ROUND: 'ROUND'; +SIGN: 'SIGN'; +SQRT: 'SQRT'; +TRUNCATE: 'TRUNCATE'; + +// TRIGONOMETRIC FUNCTIONS +ACOS: 'ACOS'; +ASIN: 'ASIN'; +ATAN: 'ATAN'; +ATAN2: 'ATAN2'; +COS: 'COS'; +COT: 'COT'; +DEGREES: 'DEGREES'; +RADIANS: 'RADIANS'; +SIN: 'SIN'; +TAN: 'TAN'; + +// DATE AND TIME FUNCTIONS +ADDDATE: 'ADDDATE'; +ADDTIME: 'ADDTIME'; +CURDATE: 'CURDATE'; +CURRENT_DATE: 'CURRENT_DATE'; +CURRENT_TIME: 'CURRENT_TIME'; +CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'; +CURTIME: 'CURTIME'; +DATE: 'DATE'; +DATEDIFF: 'DATEDIFF'; +DATE_ADD: 'DATE_ADD'; +DATE_FORMAT: 'DATE_FORMAT'; +DATE_SUB: 'DATE_SUB'; +DAYNAME: 'DAYNAME'; +DAYOFMONTH: 'DAYOFMONTH'; +DAYOFWEEK: 'DAYOFWEEK'; +DAYOFYEAR: 'DAYOFYEAR'; +DAY_OF_MONTH: 'DAY_OF_MONTH'; +DAY_OF_WEEK: 'DAY_OF_WEEK'; +EXTRACT: 'EXTRACT'; +FROM_DAYS: 'FROM_DAYS'; +FROM_UNIXTIME: 'FROM_UNIXTIME'; +GET_FORMAT: 'GET_FORMAT'; +LAST_DAY: 'LAST_DAY'; +LOCALTIME: 'LOCALTIME'; +LOCALTIMESTAMP: 'LOCALTIMESTAMP'; +MAKEDATE: 'MAKEDATE'; +MAKETIME: 'MAKETIME'; +MONTHNAME: 'MONTHNAME'; +NOW: 'NOW'; +PERIOD_ADD: 'PERIOD_ADD'; +PERIOD_DIFF: 'PERIOD_DIFF'; +SEC_TO_TIME: 'SEC_TO_TIME'; +STR_TO_DATE: 'STR_TO_DATE'; +SUBDATE: 'SUBDATE'; +SUBTIME: 'SUBTIME'; +SYSDATE: 'SYSDATE'; +TIME: 'TIME'; +TIMEDIFF: 'TIMEDIFF'; +TIMESTAMP: 'TIMESTAMP'; +TIMESTAMPADD: 'TIMESTAMPADD'; +TIMESTAMPDIFF: 'TIMESTAMPDIFF'; +TIME_FORMAT: 'TIME_FORMAT'; +TIME_TO_SEC: 'TIME_TO_SEC'; +TO_DAYS: 'TO_DAYS'; +TO_SECONDS: 'TO_SECONDS'; +UNIX_TIMESTAMP: 'UNIX_TIMESTAMP'; +UTC_DATE: 'UTC_DATE'; +UTC_TIME: 'UTC_TIME'; +UTC_TIMESTAMP: 'UTC_TIMESTAMP'; +WEEKDAY: 'WEEKDAY'; +YEARWEEK: 'YEARWEEK'; + +// TEXT FUNCTIONS +SUBSTR: 'SUBSTR'; +SUBSTRING: 'SUBSTRING'; +LTRIM: 'LTRIM'; +RTRIM: 'RTRIM'; +TRIM: 'TRIM'; +TO: 'TO'; +LOWER: 'LOWER'; +UPPER: 'UPPER'; +CONCAT: 'CONCAT'; +CONCAT_WS: 'CONCAT_WS'; +LENGTH: 'LENGTH'; +STRCMP: 'STRCMP'; +RIGHT: 'RIGHT'; +LEFT: 'LEFT'; +ASCII: 'ASCII'; +LOCATE: 'LOCATE'; +REPLACE: 'REPLACE'; +REVERSE: 'REVERSE'; +CAST: 'CAST'; + +// BOOL FUNCTIONS +LIKE: 'LIKE'; +ISNULL: 'ISNULL'; +ISNOTNULL: 'ISNOTNULL'; + +// FLOWCONTROL FUNCTIONS +IFNULL: 'IFNULL'; +NULLIF: 'NULLIF'; +IF: 'IF'; +TYPEOF: 'TYPEOF'; + +// RELEVANCE FUNCTIONS AND PARAMETERS +MATCH: 'MATCH'; +MATCH_PHRASE: 'MATCH_PHRASE'; +MATCH_PHRASE_PREFIX: 'MATCH_PHRASE_PREFIX'; +MATCH_BOOL_PREFIX: 'MATCH_BOOL_PREFIX'; +SIMPLE_QUERY_STRING: 'SIMPLE_QUERY_STRING'; +MULTI_MATCH: 'MULTI_MATCH'; +QUERY_STRING: 'QUERY_STRING'; + +ALLOW_LEADING_WILDCARD: 'ALLOW_LEADING_WILDCARD'; +ANALYZE_WILDCARD: 'ANALYZE_WILDCARD'; +ANALYZER: 'ANALYZER'; +AUTO_GENERATE_SYNONYMS_PHRASE_QUERY:'AUTO_GENERATE_SYNONYMS_PHRASE_QUERY'; +BOOST: 'BOOST'; +CUTOFF_FREQUENCY: 'CUTOFF_FREQUENCY'; +DEFAULT_FIELD: 'DEFAULT_FIELD'; +DEFAULT_OPERATOR: 'DEFAULT_OPERATOR'; +ENABLE_POSITION_INCREMENTS: 'ENABLE_POSITION_INCREMENTS'; +ESCAPE: 'ESCAPE'; +FLAGS: 'FLAGS'; +FUZZY_MAX_EXPANSIONS: 'FUZZY_MAX_EXPANSIONS'; +FUZZY_PREFIX_LENGTH: 'FUZZY_PREFIX_LENGTH'; +FUZZY_TRANSPOSITIONS: 'FUZZY_TRANSPOSITIONS'; +FUZZY_REWRITE: 'FUZZY_REWRITE'; +FUZZINESS: 'FUZZINESS'; +LENIENT: 'LENIENT'; +LOW_FREQ_OPERATOR: 'LOW_FREQ_OPERATOR'; +MAX_DETERMINIZED_STATES: 'MAX_DETERMINIZED_STATES'; +MAX_EXPANSIONS: 'MAX_EXPANSIONS'; +MINIMUM_SHOULD_MATCH: 'MINIMUM_SHOULD_MATCH'; +OPERATOR: 'OPERATOR'; +PHRASE_SLOP: 'PHRASE_SLOP'; +PREFIX_LENGTH: 'PREFIX_LENGTH'; +QUOTE_ANALYZER: 'QUOTE_ANALYZER'; +QUOTE_FIELD_SUFFIX: 'QUOTE_FIELD_SUFFIX'; +REWRITE: 'REWRITE'; +SLOP: 'SLOP'; +TIE_BREAKER: 'TIE_BREAKER'; +TYPE: 'TYPE'; +ZERO_TERMS_QUERY: 'ZERO_TERMS_QUERY'; + +// SPAN KEYWORDS +SPAN: 'SPAN'; +MS: 'MS'; +S: 'S'; +M: 'M'; +H: 'H'; +W: 'W'; +Q: 'Q'; +Y: 'Y'; + + +// LITERALS AND VALUES +//STRING_LITERAL: DQUOTA_STRING | SQUOTA_STRING | BQUOTA_STRING; +ID: ID_LITERAL; +CLUSTER: CLUSTER_PREFIX_LITERAL; +INTEGER_LITERAL: DEC_DIGIT+; +DECIMAL_LITERAL: (DEC_DIGIT+)? '.' DEC_DIGIT+; + +fragment DATE_SUFFIX: ([\-.][*0-9]+)+; +fragment ID_LITERAL: [@*A-Z][*A-Z_\-0-9]*; +fragment CLUSTER_PREFIX_LITERAL: [*A-Z]+?[*A-Z_\-0-9]* COLON; +ID_DATE_SUFFIX: CLUSTER_PREFIX_LITERAL? ID_LITERAL DATE_SUFFIX; +DQUOTA_STRING: '"' ( '\\'. | '""' | ~('"'| '\\') )* '"'; +SQUOTA_STRING: '\'' ('\\'. | '\'\'' | ~('\'' | '\\'))* '\''; +BQUOTA_STRING: '`' ( '\\'. | '``' | ~('`'|'\\'))* '`'; +fragment DEC_DIGIT: [0-9]; + + +ERROR_RECOGNITION: . -> channel(ERRORCHANNEL); \ No newline at end of file diff --git a/src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLParser.g4 b/src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLParser.g4 new file mode 100644 index 000000000000..944e6309f7a0 --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/grammar/OpenSearchPPLParser.g4 @@ -0,0 +1,914 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + + +parser grammar OpenSearchPPLParser; + + +options { tokenVocab = OpenSearchPPLLexer; } +root + : pplStatement? EOF + ; + +// statement +pplStatement + : dmlStatement + ; + +dmlStatement + : queryStatement + ; + +queryStatement + : pplCommands (PIPE commands)* + ; + +// commands +pplCommands + : searchCommand + | describeCommand + | showDataSourcesCommand + ; + +commands + : whereCommand + | fieldsCommand + | renameCommand + | statsCommand + | dedupCommand + | sortCommand + | evalCommand + | headCommand + | topCommand + | rareCommand + | grokCommand + | parseCommand + | patternsCommand + | kmeansCommand + | adCommand + | mlCommand + ; + +searchCommand + : (SEARCH)? fromClause # searchFrom + | (SEARCH)? fromClause logicalExpression # searchFromFilter + | (SEARCH)? logicalExpression fromClause # searchFilterFrom + ; + +describeCommand + : DESCRIBE tableSourceClause + ; + +showDataSourcesCommand + : SHOW DATASOURCES + ; + +whereCommand + : WHERE logicalExpression + ; + +fieldsCommand + : FIELDS (PLUS | MINUS)? fieldList + ; + +renameCommand + : RENAME renameClasue (COMMA renameClasue)* + ; + +statsCommand + : STATS (PARTITIONS EQUAL partitions = integerLiteral)? (ALLNUM EQUAL allnum = booleanLiteral)? (DELIM EQUAL delim = stringLiteral)? statsAggTerm (COMMA statsAggTerm)* (statsByClause)? (DEDUP_SPLITVALUES EQUAL dedupsplit = booleanLiteral)? + ; + +dedupCommand + : DEDUP (number = integerLiteral)? fieldList (KEEPEMPTY EQUAL keepempty = booleanLiteral)? (CONSECUTIVE EQUAL consecutive = booleanLiteral)? + ; + +sortCommand + : SORT sortbyClause + ; + +evalCommand + : EVAL evalClause (COMMA evalClause)* + ; + +headCommand + : HEAD (number = integerLiteral)? (FROM from = integerLiteral)? + ; + +topCommand + : TOP (number = integerLiteral)? fieldList (byClause)? + ; + +rareCommand + : RARE fieldList (byClause)? + ; + +grokCommand + : GROK (source_field = expression) (pattern = stringLiteral) + ; + +parseCommand + : PARSE (source_field = expression) (pattern = stringLiteral) + ; + +patternsCommand + : PATTERNS (patternsParameter)* (source_field = expression) + ; + +patternsParameter + : (NEW_FIELD EQUAL new_field = stringLiteral) + | (PATTERN EQUAL pattern = stringLiteral) + ; + +patternsMethod + : PUNCT + | REGEX + ; + +kmeansCommand + : KMEANS (kmeansParameter)* + ; + +kmeansParameter + : (CENTROIDS EQUAL centroids = integerLiteral) + | (ITERATIONS EQUAL iterations = integerLiteral) + | (DISTANCE_TYPE EQUAL distance_type = stringLiteral) + ; + +adCommand + : AD (adParameter)* + ; + +adParameter + : (NUMBER_OF_TREES EQUAL number_of_trees = integerLiteral) + | (SHINGLE_SIZE EQUAL shingle_size = integerLiteral) + | (SAMPLE_SIZE EQUAL sample_size = integerLiteral) + | (OUTPUT_AFTER EQUAL output_after = integerLiteral) + | (TIME_DECAY EQUAL time_decay = decimalLiteral) + | (ANOMALY_RATE EQUAL anomaly_rate = decimalLiteral) + | (CATEGORY_FIELD EQUAL category_field = stringLiteral) + | (TIME_FIELD EQUAL time_field = stringLiteral) + | (DATE_FORMAT EQUAL date_format = stringLiteral) + | (TIME_ZONE EQUAL time_zone = stringLiteral) + | (TRAINING_DATA_SIZE EQUAL training_data_size = integerLiteral) + | (ANOMALY_SCORE_THRESHOLD EQUAL anomaly_score_threshold = decimalLiteral) + ; + +mlCommand + : ML (mlArg)* + ; + +mlArg + : (argName = ident EQUAL argValue = literalValue) + ; + +// clauses +fromClause + : SOURCE EQUAL tableSourceClause + | INDEX EQUAL tableSourceClause + | SOURCE EQUAL tableFunction + | INDEX EQUAL tableFunction + ; + +tableSourceClause + : tableSource (COMMA tableSource)* + ; + +renameClasue + : orignalField = wcFieldExpression AS renamedField = wcFieldExpression + ; + +byClause + : BY fieldList + ; + +statsByClause + : BY fieldList + | BY bySpanClause + | BY bySpanClause COMMA fieldList + ; + +bySpanClause + : spanClause (AS alias = qualifiedName)? + ; + +spanClause + : SPAN LT_PRTHS fieldExpression COMMA value = literalValue (unit = timespanUnit)? RT_PRTHS + ; + +sortbyClause + : sortField (COMMA sortField)* + ; + +evalClause + : fieldExpression EQUAL expression + ; + +// aggregation terms +statsAggTerm + : statsFunction (AS alias = wcFieldExpression)? + ; + +// aggregation functions +statsFunction + : statsFunctionName LT_PRTHS valueExpression RT_PRTHS # statsFunctionCall + | COUNT LT_PRTHS RT_PRTHS # countAllFunctionCall + | (DISTINCT_COUNT | DC) LT_PRTHS valueExpression RT_PRTHS # distinctCountFunctionCall + | percentileAggFunction # percentileAggFunctionCall + | takeAggFunction # takeAggFunctionCall + ; + +statsFunctionName + : AVG + | COUNT + | SUM + | MIN + | MAX + | VAR_SAMP + | VAR_POP + | STDDEV_SAMP + | STDDEV_POP + ; + +takeAggFunction + : TAKE LT_PRTHS fieldExpression (COMMA size = integerLiteral)? RT_PRTHS + ; + +percentileAggFunction + : PERCENTILE LESS value = integerLiteral GREATER LT_PRTHS aggField = fieldExpression RT_PRTHS + ; + +// expressions +expression + : logicalExpression + | comparisonExpression + | valueExpression + ; + +logicalExpression + : comparisonExpression # comparsion + | NOT logicalExpression # logicalNot + | left = logicalExpression OR right = logicalExpression # logicalOr + | left = logicalExpression (AND)? right = logicalExpression # logicalAnd + | left = logicalExpression XOR right = logicalExpression # logicalXor + | booleanExpression # booleanExpr + | relevanceExpression # relevanceExpr + ; + +comparisonExpression + : left = valueExpression comparisonOperator right = valueExpression # compareExpr + | valueExpression IN valueList # inExpr + ; + +valueExpression + : left = valueExpression binaryOperator = (STAR | DIVIDE | MODULE) right = valueExpression # binaryArithmetic + | left = valueExpression binaryOperator = (PLUS | MINUS) right = valueExpression # binaryArithmetic + | primaryExpression # valueExpressionDefault + | positionFunction # positionFunctionCall + | extractFunction # extractFunctionCall + | getFormatFunction # getFormatFunctionCall + | timestampFunction # timestampFunctionCall + | LT_PRTHS valueExpression RT_PRTHS # parentheticValueExpr + ; + +primaryExpression + : evalFunctionCall + | dataTypeFunctionCall + | fieldExpression + | literalValue + ; + +positionFunction + : positionFunctionName LT_PRTHS functionArg IN functionArg RT_PRTHS + ; + +booleanExpression + : booleanFunctionCall + ; + +relevanceExpression + : singleFieldRelevanceFunction + | multiFieldRelevanceFunction + ; + +// Field is a single column +singleFieldRelevanceFunction + : singleFieldRelevanceFunctionName LT_PRTHS field = relevanceField COMMA query = relevanceQuery (COMMA relevanceArg)* RT_PRTHS + ; + +// Field is a list of columns +multiFieldRelevanceFunction + : multiFieldRelevanceFunctionName LT_PRTHS LT_SQR_PRTHS field = relevanceFieldAndWeight (COMMA field = relevanceFieldAndWeight)* RT_SQR_PRTHS COMMA query = relevanceQuery (COMMA relevanceArg)* RT_PRTHS + ; + +// tables +tableSource + : tableQualifiedName + | ID_DATE_SUFFIX + ; + +tableFunction + : qualifiedName LT_PRTHS functionArgs RT_PRTHS + ; + +// fields +fieldList + : fieldExpression (COMMA fieldExpression)* + ; + +wcFieldList + : wcFieldExpression (COMMA wcFieldExpression)* + ; + +sortField + : (PLUS | MINUS)? sortFieldExpression + ; + +sortFieldExpression + : fieldExpression + | AUTO LT_PRTHS fieldExpression RT_PRTHS + | STR LT_PRTHS fieldExpression RT_PRTHS + | IP LT_PRTHS fieldExpression RT_PRTHS + | NUM LT_PRTHS fieldExpression RT_PRTHS + ; + +fieldExpression + : qualifiedName + ; + +wcFieldExpression + : wcQualifiedName + ; + +// functions +evalFunctionCall + : evalFunctionName LT_PRTHS functionArgs RT_PRTHS + ; + +// cast function +dataTypeFunctionCall + : CAST LT_PRTHS expression AS convertedDataType RT_PRTHS + ; + +// boolean functions +booleanFunctionCall + : conditionFunctionBase LT_PRTHS functionArgs RT_PRTHS + ; + +convertedDataType + : typeName = DATE + | typeName = TIME + | typeName = TIMESTAMP + | typeName = INT + | typeName = INTEGER + | typeName = DOUBLE + | typeName = LONG + | typeName = FLOAT + | typeName = STRING + | typeName = BOOLEAN + ; + +evalFunctionName + : mathematicalFunctionName + | dateTimeFunctionName + | textFunctionName + | conditionFunctionBase + | systemFunctionName + | positionFunctionName + ; + +functionArgs + : (functionArg (COMMA functionArg)*)? + ; + +functionArg + : (ident EQUAL)? valueExpression + ; + +relevanceArg + : relevanceArgName EQUAL relevanceArgValue + ; + +relevanceArgName + : ALLOW_LEADING_WILDCARD + | ANALYZER + | ANALYZE_WILDCARD + | AUTO_GENERATE_SYNONYMS_PHRASE_QUERY + | BOOST + | CUTOFF_FREQUENCY + | DEFAULT_FIELD + | DEFAULT_OPERATOR + | ENABLE_POSITION_INCREMENTS + | ESCAPE + | FIELDS + | FLAGS + | FUZZINESS + | FUZZY_MAX_EXPANSIONS + | FUZZY_PREFIX_LENGTH + | FUZZY_REWRITE + | FUZZY_TRANSPOSITIONS + | LENIENT + | LOW_FREQ_OPERATOR + | MAX_DETERMINIZED_STATES + | MAX_EXPANSIONS + | MINIMUM_SHOULD_MATCH + | OPERATOR + | PHRASE_SLOP + | PREFIX_LENGTH + | QUOTE_ANALYZER + | QUOTE_FIELD_SUFFIX + | REWRITE + | SLOP + | TIE_BREAKER + | TIME_ZONE + | TYPE + | ZERO_TERMS_QUERY + ; + +relevanceFieldAndWeight + : field = relevanceField + | field = relevanceField weight = relevanceFieldWeight + | field = relevanceField BIT_XOR_OP weight = relevanceFieldWeight + ; + +relevanceFieldWeight + : integerLiteral + | decimalLiteral + ; + +relevanceField + : qualifiedName + | stringLiteral + ; + +relevanceQuery + : relevanceArgValue + ; + +relevanceArgValue + : qualifiedName + | literalValue + ; + +mathematicalFunctionName + : ABS + | CBRT + | CEIL + | CEILING + | CONV + | CRC32 + | E + | EXP + | FLOOR + | LN + | LOG + | LOG10 + | LOG2 + | MOD + | PI + | POW + | POWER + | RAND + | ROUND + | SIGN + | SQRT + | TRUNCATE + | trigonometricFunctionName + ; + +trigonometricFunctionName + : ACOS + | ASIN + | ATAN + | ATAN2 + | COS + | COT + | DEGREES + | RADIANS + | SIN + | TAN + ; + +dateTimeFunctionName + : ADDDATE + | ADDTIME + | CONVERT_TZ + | CURDATE + | CURRENT_DATE + | CURRENT_TIME + | CURRENT_TIMESTAMP + | CURTIME + | DATE + | DATEDIFF + | DATETIME + | DATE_ADD + | DATE_FORMAT + | DATE_SUB + | DAY + | DAYNAME + | DAYOFMONTH + | DAYOFWEEK + | DAYOFYEAR + | DAY_OF_MONTH + | DAY_OF_WEEK + | DAY_OF_YEAR + | FROM_DAYS + | FROM_UNIXTIME + | HOUR + | HOUR_OF_DAY + | LAST_DAY + | LOCALTIME + | LOCALTIMESTAMP + | MAKEDATE + | MAKETIME + | MICROSECOND + | MINUTE + | MINUTE_OF_DAY + | MINUTE_OF_HOUR + | MONTH + | MONTHNAME + | MONTH_OF_YEAR + | NOW + | PERIOD_ADD + | PERIOD_DIFF + | QUARTER + | SECOND + | SECOND_OF_MINUTE + | SEC_TO_TIME + | STR_TO_DATE + | SUBDATE + | SUBTIME + | SYSDATE + | TIME + | TIMEDIFF + | TIMESTAMP + | TIME_FORMAT + | TIME_TO_SEC + | TO_DAYS + | TO_SECONDS + | UNIX_TIMESTAMP + | UTC_DATE + | UTC_TIME + | UTC_TIMESTAMP + | WEEK + | WEEKDAY + | WEEK_OF_YEAR + | YEAR + | YEARWEEK + ; + +getFormatFunction + : GET_FORMAT LT_PRTHS getFormatType COMMA functionArg RT_PRTHS + ; + +getFormatType + : DATE + | DATETIME + | TIME + | TIMESTAMP + ; + +extractFunction + : EXTRACT LT_PRTHS datetimePart FROM functionArg RT_PRTHS + ; + +simpleDateTimePart + : MICROSECOND + | SECOND + | MINUTE + | HOUR + | DAY + | WEEK + | MONTH + | QUARTER + | YEAR + ; + +complexDateTimePart + : SECOND_MICROSECOND + | MINUTE_MICROSECOND + | MINUTE_SECOND + | HOUR_MICROSECOND + | HOUR_SECOND + | HOUR_MINUTE + | DAY_MICROSECOND + | DAY_SECOND + | DAY_MINUTE + | DAY_HOUR + | YEAR_MONTH + ; + +datetimePart + : simpleDateTimePart + | complexDateTimePart + ; + +timestampFunction + : timestampFunctionName LT_PRTHS simpleDateTimePart COMMA firstArg = functionArg COMMA secondArg = functionArg RT_PRTHS + ; + +timestampFunctionName + : TIMESTAMPADD + | TIMESTAMPDIFF + ; + +// condition function return boolean value +conditionFunctionBase + : LIKE + | IF + | ISNULL + | ISNOTNULL + | IFNULL + | NULLIF + ; + +systemFunctionName + : TYPEOF + ; + +textFunctionName + : SUBSTR + | SUBSTRING + | TRIM + | LTRIM + | RTRIM + | LOWER + | UPPER + | CONCAT + | CONCAT_WS + | LENGTH + | STRCMP + | RIGHT + | LEFT + | ASCII + | LOCATE + | REPLACE + | REVERSE + ; + +positionFunctionName + : POSITION + ; + +// operators + comparisonOperator + : EQUAL + | NOT_EQUAL + | LESS + | NOT_LESS + | GREATER + | NOT_GREATER + | REGEXP + ; + +singleFieldRelevanceFunctionName + : MATCH + | MATCH_PHRASE + | MATCH_BOOL_PREFIX + | MATCH_PHRASE_PREFIX + ; + +multiFieldRelevanceFunctionName + : SIMPLE_QUERY_STRING + | MULTI_MATCH + | QUERY_STRING + ; + +// literals and values +literalValue + : intervalLiteral + | stringLiteral + | integerLiteral + | decimalLiteral + | booleanLiteral + | datetimeLiteral //#datetime + ; + +intervalLiteral + : INTERVAL valueExpression intervalUnit + ; + +stringLiteral + : DQUOTA_STRING + | SQUOTA_STRING + ; + +integerLiteral + : (PLUS | MINUS)? INTEGER_LITERAL + ; + +decimalLiteral + : (PLUS | MINUS)? DECIMAL_LITERAL + ; + +booleanLiteral + : TRUE + | FALSE + ; + +// Date and Time Literal, follow ANSI 92 +datetimeLiteral + : dateLiteral + | timeLiteral + | timestampLiteral + ; + +dateLiteral + : DATE date = stringLiteral + ; + +timeLiteral + : TIME time = stringLiteral + ; + +timestampLiteral + : TIMESTAMP timestamp = stringLiteral + ; + +intervalUnit + : MICROSECOND + | SECOND + | MINUTE + | HOUR + | DAY + | WEEK + | MONTH + | QUARTER + | YEAR + | SECOND_MICROSECOND + | MINUTE_MICROSECOND + | MINUTE_SECOND + | HOUR_MICROSECOND + | HOUR_SECOND + | HOUR_MINUTE + | DAY_MICROSECOND + | DAY_SECOND + | DAY_MINUTE + | DAY_HOUR + | YEAR_MONTH + ; + +timespanUnit + : MS + | S + | M + | H + | D + | W + | Q + | Y + | MILLISECOND + | SECOND + | MINUTE + | HOUR + | DAY + | WEEK + | MONTH + | QUARTER + | YEAR + ; + +valueList + : LT_PRTHS literalValue (COMMA literalValue)* RT_PRTHS + ; + +qualifiedName + : ident (DOT ident)* # identsAsQualifiedName + ; + +tableQualifiedName + : tableIdent (DOT ident)* # identsAsTableQualifiedName + ; + +wcQualifiedName + : wildcard (DOT wildcard)* # identsAsWildcardQualifiedName + ; + +ident + : (DOT)? ID + | BACKTICK ident BACKTICK + | BQUOTA_STRING + | keywordsCanBeId + ; + +tableIdent + : (CLUSTER)? ident + ; + +wildcard + : ident (MODULE ident)* (MODULE)? + | SINGLE_QUOTE wildcard SINGLE_QUOTE + | DOUBLE_QUOTE wildcard DOUBLE_QUOTE + | BACKTICK wildcard BACKTICK + ; + +keywordsCanBeId + : D // OD SQL and ODBC special + | timespanUnit + | SPAN + | evalFunctionName + | relevanceArgName + | intervalUnit + | dateTimeFunctionName + | textFunctionName + | mathematicalFunctionName + | positionFunctionName + // commands + | SEARCH + | DESCRIBE + | SHOW + | FROM + | WHERE + | FIELDS + | RENAME + | STATS + | DEDUP + | SORT + | EVAL + | HEAD + | TOP + | RARE + | PARSE + | METHOD + | REGEX + | PUNCT + | GROK + | PATTERN + | PATTERNS + | NEW_FIELD + | KMEANS + | AD + | ML + // commands assist keywords + | SOURCE + | INDEX + | DESC + | DATASOURCES + // CLAUSEKEYWORDS + | SORTBY + // FIELDKEYWORDSAUTO + | STR + | IP + | NUM + // ARGUMENT KEYWORDS + | KEEPEMPTY + | CONSECUTIVE + | DEDUP_SPLITVALUES + | PARTITIONS + | ALLNUM + | DELIM + | CENTROIDS + | ITERATIONS + | DISTANCE_TYPE + | NUMBER_OF_TREES + | SHINGLE_SIZE + | SAMPLE_SIZE + | OUTPUT_AFTER + | TIME_DECAY + | ANOMALY_RATE + | CATEGORY_FIELD + | TIME_FIELD + | TIME_ZONE + | TRAINING_DATA_SIZE + | ANOMALY_SCORE_THRESHOLD + // AGGREGATIONS + | AVG + | COUNT + | DISTINCT_COUNT + | ESTDC + | ESTDC_ERROR + | MAX + | MEAN + | MEDIAN + | MIN + | MODE + | RANGE + | STDEV + | STDEVP + | SUM + | SUMSQ + | VAR_SAMP + | VAR_POP + | STDDEV_SAMP + | STDDEV_POP + | PERCENTILE + | TAKE + | FIRST + | LAST + | LIST + | VALUES + | EARLIEST + | EARLIEST_TIME + | LATEST + | LATEST_TIME + | PER_DAY + | PER_HOUR + | PER_MINUTE + | PER_SECOND + | RATE + | SPARKLINE + | C + | DC + ; \ No newline at end of file diff --git a/src/plugins/data/public/antlr/opensearch_ppl/opensearch_ppl_autocomplete.ts b/src/plugins/data/public/antlr/opensearch_ppl/opensearch_ppl_autocomplete.ts new file mode 100644 index 000000000000..db1cb320035d --- /dev/null +++ b/src/plugins/data/public/antlr/opensearch_ppl/opensearch_ppl_autocomplete.ts @@ -0,0 +1,146 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as c3 from 'antlr4-c3'; +import { ParseTree, TokenStream } from 'antlr4ng'; +import { + AutocompleteData, + AutocompleteResultBase, + CursorPosition, + OpenSearchPplAutocompleteResult, + ProcessVisitedRulesResult, +} from '../shared/types'; +import { OpenSearchPPLLexer } from './.generated/OpenSearchPPLLexer'; +import { OpenSearchPPLParser } from './.generated/OpenSearchPPLParser'; + +// These are keywords that we do not want to show in autocomplete +export function getIgnoredTokens(): number[] { + const tokens = [OpenSearchPPLParser.SPACE, OpenSearchPPLParser.EOF]; + + const firstOperatorIndex = OpenSearchPPLParser.MATCH; + const lastOperatorIndex = OpenSearchPPLParser.ERROR_RECOGNITION; + for (let i = firstOperatorIndex; i <= lastOperatorIndex; i++) { + tokens.push(i); + } + + const firstFunctionIndex = OpenSearchPPLParser.CASE; + const lastFunctionIndex = OpenSearchPPLParser.CAST; + const operatorsToInclude = [ + OpenSearchPPLParser.PIPE, + OpenSearchPPLParser.EQUAL, + OpenSearchPPLParser.COMMA, + ]; + for (let i = firstFunctionIndex; i <= lastFunctionIndex; i++) { + if (!operatorsToInclude.includes(i)) { + tokens.push(i); + } + } + + return tokens; +} + +const ignoredTokens = new Set(getIgnoredTokens()); +const tokenDictionary: any = { + SPACE: OpenSearchPPLParser.SPACE, + FROM: OpenSearchPPLParser.FROM, + OPENING_BRACKET: OpenSearchPPLParser.LT_PRTHS, + CLOSING_BRACKET: OpenSearchPPLParser.RT_PRTHS, + SEARCH: OpenSearchPPLParser.SEARCH, + SOURCE: OpenSearchPPLParser.SOURCE, +}; + +const rulesToVisit = new Set([ + OpenSearchPPLParser.RULE_fieldExpression, + OpenSearchPPLParser.RULE_statsFunctionName, + OpenSearchPPLParser.RULE_percentileAggFunction, + OpenSearchPPLParser.RULE_takeAggFunction, + OpenSearchPPLParser.RULE_timestampFunctionName, + OpenSearchPPLParser.RULE_getFormatFunction, + OpenSearchPPLParser.RULE_tableQualifiedName, + OpenSearchPPLParser.RULE_singleFieldRelevanceFunctionName, + OpenSearchPPLParser.RULE_multiFieldRelevanceFunctionName, + OpenSearchPPLParser.RULE_positionFunctionName, + OpenSearchPPLParser.RULE_evalFunctionName, +]); + +export function processVisitedRules( + rules: c3.CandidatesCollection['rules'], + cursorTokenIndex: number, + tokenStream: TokenStream +): ProcessVisitedRulesResult { + let suggestSourcesOrTables: OpenSearchPplAutocompleteResult['suggestSourcesOrTables']; + let suggestAggregateFunctions = false; + let shouldSuggestColumns = false; + + for (const [ruleId, rule] of rules) { + switch (ruleId) { + case OpenSearchPPLParser.RULE_statsFunctionName: { + suggestAggregateFunctions = true; + break; + } + case OpenSearchPPLParser.RULE_fieldExpression: { + shouldSuggestColumns = true; + break; + } + } + } + + return { + suggestSourcesOrTables, + suggestAggregateFunctions, + shouldSuggestColumns, + }; +} + +export function getParseTree(parser: OpenSearchPPLParser, type?: 'search' | 'from'): ParseTree { + if (!type) { + return parser.root(); + } + + switch (type) { + case 'from': + return parser.fromClause(); + case 'search': + return parser.searchCommand(); + default: + return parser.root(); + } +} + +export function enrichAutocompleteResult( + baseResult: AutocompleteResultBase, + rules: c3.CandidatesCollection['rules'], + tokenStream: TokenStream, + cursorTokenIndex: number, + cursor: CursorPosition, + query: string +): OpenSearchPplAutocompleteResult { + const { + shouldSuggestColumns, + shouldSuggestColumnAliases, + shouldSuggestConstraints, + ...suggestionsFromRules + } = processVisitedRules(rules, cursorTokenIndex, tokenStream); + const result: OpenSearchPplAutocompleteResult = { + ...baseResult, + ...suggestionsFromRules, + suggestColumns: shouldSuggestColumns ? shouldSuggestColumns : undefined, + }; + return result; +} + +export const openSearchPplAutocompleteData: AutocompleteData< + any, + OpenSearchPPLLexer, + OpenSearchPPLParser +> = { + Lexer: OpenSearchPPLLexer, + Parser: OpenSearchPPLParser, + tokenDictionary, + ignoredTokens, + rulesToVisit, + getParseTree, + enrichAutocompleteResult, +}; diff --git a/src/plugins/data/public/antlr/opensearch_sql/code_completion.ts b/src/plugins/data/public/antlr/opensearch_sql/code_completion.ts index bfd0d9d2da9c..a0695a424393 100644 --- a/src/plugins/data/public/antlr/opensearch_sql/code_completion.ts +++ b/src/plugins/data/public/antlr/opensearch_sql/code_completion.ts @@ -4,27 +4,12 @@ */ import { monaco } from '@osd/monaco'; -import { Lexer as LexerType, ParserRuleContext, Parser as ParserType } from 'antlr4ng'; -import { CodeCompletionCore } from 'antlr4-c3'; -import { - AutocompleteResultBase, - CursorPosition, - EnrichAutocompleteResult, - GetParseTree, - KeywordSuggestion, - LexerConstructor, - OpenSearchSqlAutocompleteResult, - ParserConstructor, -} from '../shared/types'; -import { TokenDictionary } from './table'; -import { createParser } from './parse'; -import { SqlErrorListener } from './sql_error_listerner'; -import { findCursorTokenIndex } from '../shared/cursor'; +import { CursorPosition, OpenSearchSqlAutocompleteResult } from '../shared/types'; import { openSearchSqlAutocompleteData } from './opensearch_sql_autocomplete'; import { SQL_SYMBOLS } from './constants'; import { QuerySuggestion, QuerySuggestionGetFnArgs } from '../../autocomplete'; -import { fetchTableSchemas } from '../shared/utils'; -import { IDataFrameResponse, IFieldType } from '../../../common'; +import { fetchFieldSuggestions, parseQuery } from '../shared/utils'; +import { SuggestionItemDetailsTags } from '../shared/constants'; export interface SuggestionParams { position: monaco.Position; @@ -37,46 +22,29 @@ export interface ISuggestionItem { fieldType?: string; } -const quotesRegex = /^'(.*)'$/; - export const getSuggestions = async ({ selectionStart, selectionEnd, + indexPattern, position, query, services, }: QuerySuggestionGetFnArgs): Promise => { - const { api } = services.uiSettings; - const queryString = services.data.query.queryString; - const { lineNumber, column } = position || {}; - const suggestions = getOpenSearchSqlAutoCompleteSuggestions(query, { - line: lineNumber || selectionStart, - column: column || selectionEnd, - }); + if (!services || !services.appName || !indexPattern) return []; + try { + const { lineNumber, column } = position || {}; + const suggestions = getOpenSearchSqlAutoCompleteSuggestions(query, { + line: lineNumber || selectionStart, + column: column || selectionEnd, + }); - const finalSuggestions: QuerySuggestion[] = []; + const finalSuggestions: QuerySuggestion[] = []; - try { // Fetch columns and values if (suggestions.suggestColumns?.tables?.length) { - const tableNames = suggestions.suggestColumns.tables.map((table) => table.name); - const schemas = await fetchTableSchemas(tableNames, api, queryString); - - (schemas as IDataFrameResponse[]).forEach((schema: IDataFrameResponse) => { - if ('body' in schema && schema.body && 'fields' in schema.body) { - const columns = schema.body.fields.find((col: IFieldType) => col.name === 'COLUMN_NAME'); - const fieldTypes = schema.body.fields.find((col: IFieldType) => col.name === 'DATA_TYPE'); - - if (columns && fieldTypes) { - finalSuggestions.push( - ...columns.values.map((col: string) => ({ - text: col, - type: monaco.languages.CompletionItemKind.Field, - })) - ); - } - } - }); + // NOTE: currently the suggestions return the table present in the query, but since the + // parameters already provide that, it may not be needed anymore + finalSuggestions.push(...fetchFieldSuggestions(indexPattern)); } // Fill in aggregate functions @@ -85,6 +53,8 @@ export const getSuggestions = async ({ ...SQL_SYMBOLS.AGREGATE_FUNCTIONS.map((af) => ({ text: af, type: monaco.languages.CompletionItemKind.Function, + insertText: af, + detail: SuggestionItemDetailsTags.AggregateFunction, })) ); } @@ -95,85 +65,16 @@ export const getSuggestions = async ({ ...suggestions.suggestKeywords.map((sk) => ({ text: sk.value, type: monaco.languages.CompletionItemKind.Keyword, + insertText: sk.value, + detail: SuggestionItemDetailsTags.Keyword, })) ); } + return finalSuggestions; } catch (error) { // TODO: Handle errors appropriately, possibly logging or displaying a message to the user return []; } - - return finalSuggestions; -}; - -export interface ParsingSubject { - Lexer: LexerConstructor; - Parser: ParserConstructor

; - tokenDictionary: TokenDictionary; - ignoredTokens: Set; - rulesToVisit: Set; - getParseTree: GetParseTree

; - enrichAutocompleteResult: EnrichAutocompleteResult; - query: string; - cursor: CursorPosition; - context?: ParserRuleContext; -} - -export const parseQuery = < - A extends AutocompleteResultBase, - L extends LexerType, - P extends ParserType ->({ - Lexer, - Parser, - tokenDictionary, - ignoredTokens, - rulesToVisit, - getParseTree, - enrichAutocompleteResult, - query, - cursor, - context, -}: ParsingSubject) => { - const parser = createParser(Lexer, Parser, query); - const { tokenStream } = parser; - const errorListener = new SqlErrorListener(tokenDictionary.SPACE); - - parser.removeErrorListeners(); - parser.addErrorListener(errorListener); - getParseTree(parser); - - const core = new CodeCompletionCore(parser); - core.ignoredTokens = ignoredTokens; - core.preferredRules = rulesToVisit; - const cursorTokenIndex = findCursorTokenIndex(tokenStream, cursor, tokenDictionary.SPACE); - if (cursorTokenIndex === undefined) { - throw new Error( - `Could not find cursor token index for line: ${cursor.line}, column: ${cursor.column}` - ); - } - - const suggestKeywords: KeywordSuggestion[] = []; - const { tokens, rules } = core.collectCandidates(cursorTokenIndex, context); - tokens.forEach((_, tokenType) => { - // Literal keyword names are quoted - const literalName = parser.vocabulary.getLiteralName(tokenType)?.replace(quotesRegex, '$1'); - - if (!literalName) { - throw new Error(`Could not get literal name for token ${tokenType}`); - } - - suggestKeywords.push({ - value: literalName, - }); - }); - - const result: AutocompleteResultBase = { - errors: errorListener.errors, - suggestKeywords, - }; - - return enrichAutocompleteResult(result, rules, tokenStream, cursorTokenIndex, cursor, query); }; export const getOpenSearchSqlAutoCompleteSuggestions = ( diff --git a/src/plugins/data/public/antlr/shared/constants.ts b/src/plugins/data/public/antlr/shared/constants.ts new file mode 100644 index 000000000000..bd38cedc3822 --- /dev/null +++ b/src/plugins/data/public/antlr/shared/constants.ts @@ -0,0 +1,12 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +// suggestion item details tags +export const enum SuggestionItemDetailsTags { + Keyword = 'Keyword', + AggregateFunction = 'Aggregate Function', + Value = 'Value', +} +export const quotesRegex = /^'(.*)'$/; diff --git a/src/plugins/data/public/antlr/shared/general_error_listerner.ts b/src/plugins/data/public/antlr/shared/general_error_listerner.ts new file mode 100644 index 000000000000..0bd4227169b6 --- /dev/null +++ b/src/plugins/data/public/antlr/shared/general_error_listerner.ts @@ -0,0 +1,47 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { ANTLRErrorListener, ATNSimulator, Recognizer, Token } from 'antlr4ng'; + +import { TokenPosition, getTokenPosition } from '../shared/cursor'; + +interface ParserSyntaxError extends TokenPosition { + message: string; +} + +export class GeneralErrorListener implements ANTLRErrorListener { + errors: ParserSyntaxError[]; + whitespaceToken: number; + + constructor(whitespaceToken: number) { + this.errors = []; + this.whitespaceToken = whitespaceToken; + } + + syntaxError( + _recognizer: Recognizer, + token: S | null, + startLine: number, + startColumn: number, + message: string + ): void { + if (token) { + const tokenPosition = getTokenPosition(token, this.whitespaceToken); + this.errors.push({ message, ...tokenPosition }); + } else { + this.errors.push({ + message, + startLine, + startColumn, + endLine: startLine, + endColumn: startColumn, + }); + } + } + + reportAmbiguity(): void {} + reportAttemptingFullContext(): void {} + reportContextSensitivity(): void {} +} diff --git a/src/plugins/data/public/antlr/shared/types.ts b/src/plugins/data/public/antlr/shared/types.ts index 299cb8a3c37b..8941a8469d4b 100644 --- a/src/plugins/data/public/antlr/shared/types.ts +++ b/src/plugins/data/public/antlr/shared/types.ts @@ -87,12 +87,22 @@ export interface OpenSearchSqlAutocompleteResult extends AutocompleteResultBase suggestViewsOrTables?: TableOrViewSuggestion; } +export interface OpenSearchPplAutocompleteResult extends AutocompleteResultBase { + suggestSourcesOrTables?: SourceOrTableSuggestion; +} + export enum TableOrViewSuggestion { ALL = 'ALL', TABLES = 'TABLES', VIEWS = 'VIEWS', } +export enum SourceOrTableSuggestion { + ALL = 'ALL', + TABLES = 'TABLES', + SOURCES = 'SOURCES', +} + export type ConstraintSuggestion = TableContextSuggestion; export interface ISymbolTableVisitor { @@ -122,3 +132,16 @@ export type ProcessVisitedRulesResult = Partia shouldSuggestColumnAliases?: boolean; shouldSuggestConstraints?: boolean; }; + +export interface ParsingSubject { + Lexer: LexerConstructor; + Parser: ParserConstructor

; + tokenDictionary: TokenDictionary; + ignoredTokens: Set; + rulesToVisit: Set; + getParseTree: GetParseTree

; + enrichAutocompleteResult: EnrichAutocompleteResult; + query: string; + cursor: CursorPosition; + context?: ParserRuleContext; +} diff --git a/src/plugins/data/public/antlr/shared/utils.ts b/src/plugins/data/public/antlr/shared/utils.ts index 7ae9dd18940b..6136aa0f9ae9 100644 --- a/src/plugins/data/public/antlr/shared/utils.ts +++ b/src/plugins/data/public/antlr/shared/utils.ts @@ -5,7 +5,18 @@ import { from } from 'rxjs'; import { distinctUntilChanged, startWith, switchMap } from 'rxjs/operators'; +import { CodeCompletionCore } from 'antlr4-c3'; +import { Lexer as LexerType, Parser as ParserType } from 'antlr4ng'; +import { monaco } from '@osd/monaco'; import { QueryStringContract } from '../../query'; +import { findCursorTokenIndex } from './cursor'; +import { GeneralErrorListener } from './general_error_listerner'; +import { createParser } from '../opensearch_sql/parse'; +import { AutocompleteResultBase, KeywordSuggestion } from './types'; +import { ParsingSubject } from './types'; +import { quotesRegex } from './constants'; +import { IndexPattern, IndexPatternField } from '../../index_patterns'; +import { QuerySuggestion } from '../../autocomplete'; export interface IDataSourceRequestHandlerParams { dataSourceId: string; @@ -82,6 +93,7 @@ export const fetchData = ( }; // Specific fetch function for table schemas +// TODO: remove this after using data set table schema fetcher export const fetchTableSchemas = (tables: string[], api: any, queryString: QueryStringContract) => { return fetchData( tables, @@ -100,3 +112,80 @@ export const fetchTableSchemas = (tables: string[], api: any, queryString: Query queryString ); }; + +export const fetchFieldSuggestions = ( + indexPattern: IndexPattern, + modifyInsertText?: (input: string) => string +) => { + const filteredFields = indexPattern.fields.filter( + (idxField: IndexPatternField) => !idxField?.subType + ); // filter removed .keyword fields + + const fieldSuggestions: QuerySuggestion[] = filteredFields.map((field) => { + return { + text: field.name, + type: monaco.languages.CompletionItemKind.Field, + detail: `Field: ${field.esTypes?.[0] ?? field.type}`, + ...(modifyInsertText && { insertText: modifyInsertText(field.name) }), // optionally include insert text if fn exists + }; + }); + + return fieldSuggestions; +}; + +export const parseQuery = < + A extends AutocompleteResultBase, + L extends LexerType, + P extends ParserType +>({ + Lexer, + Parser, + tokenDictionary, + ignoredTokens, + rulesToVisit, + getParseTree, + enrichAutocompleteResult, + query, + cursor, + context, +}: ParsingSubject) => { + const parser = createParser(Lexer, Parser, query); + const { tokenStream } = parser; + const errorListener = new GeneralErrorListener(tokenDictionary.SPACE); + + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + getParseTree(parser); + + const core = new CodeCompletionCore(parser); + core.ignoredTokens = ignoredTokens; + core.preferredRules = rulesToVisit; + const cursorTokenIndex = findCursorTokenIndex(tokenStream, cursor, tokenDictionary.SPACE); + if (cursorTokenIndex === undefined) { + throw new Error( + `Could not find cursor token index for line: ${cursor.line}, column: ${cursor.column}` + ); + } + + const suggestKeywords: KeywordSuggestion[] = []; + const { tokens, rules } = core.collectCandidates(cursorTokenIndex, context); + tokens.forEach((_, tokenType) => { + // Literal keyword names are quoted + const literalName = parser.vocabulary.getLiteralName(tokenType)?.replace(quotesRegex, '$1'); + + if (!literalName) { + return; + } + + suggestKeywords.push({ + value: literalName, + }); + }); + + const result: AutocompleteResultBase = { + errors: errorListener.errors, + suggestKeywords, + }; + + return enrichAutocompleteResult(result, rules, tokenStream, cursorTokenIndex, cursor, query); +}; diff --git a/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts index 636a4a1993b6..aebb4087d9db 100644 --- a/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts @@ -59,12 +59,11 @@ export interface QuerySuggestionGetFnArgs { /** @public **/ export interface QuerySuggestionBasic { - type: QuerySuggestionTypes | monaco.languages.CompletionItemKind; + type: QuerySuggestionTypes; description?: string | JSX.Element; end: number; start: number; text: string; - insertText?: string; cursorIndex?: number; } @@ -74,5 +73,17 @@ export interface QuerySuggestionField extends QuerySuggestionBasic { field: IFieldType; } +export interface MonacoCompatibleQuerySuggestion + extends Pick { + type: monaco.languages.CompletionItemKind; + text: string; + detail: string; + insertText?: string; + replacePosition?: monaco.Range; +} + /** @public **/ -export type QuerySuggestion = QuerySuggestionBasic | QuerySuggestionField; +export type QuerySuggestion = + | QuerySuggestionBasic + | QuerySuggestionField + | MonacoCompatibleQuerySuggestion; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 916909e25acb..ede785e14b84 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -91,6 +91,7 @@ import { DefaultDslDataSource } from './data_sources/default_datasource'; import { DEFAULT_DATA_SOURCE_TYPE } from './data_sources/constants'; import { getSuggestions as getSQLSuggestions } from './antlr/opensearch_sql/code_completion'; import { getSuggestions as getDQLSuggestions } from './antlr/dql/code_completion'; +import { getSuggestions as getPPLSuggestions } from './antlr/opensearch_ppl/code_completion'; import { createStorage, DataStorage } from '../common'; declare module '../../ui_actions/public' { @@ -163,9 +164,10 @@ export class DataPublicPlugin })) ); - const ac = this.autocomplete.setup(core); - ac.addQuerySuggestionProvider('SQL', getSQLSuggestions); - ac.addQuerySuggestionProvider('kuery', getDQLSuggestions); + const autoComplete = this.autocomplete.setup(core); + autoComplete.addQuerySuggestionProvider('SQL', getSQLSuggestions); + autoComplete.addQuerySuggestionProvider('kuery', getDQLSuggestions); + autoComplete.addQuerySuggestionProvider('PPL', getPPLSuggestions); return { // TODO: MQL diff --git a/src/plugins/data/public/ui/query_editor/_query_editor.scss b/src/plugins/data/public/ui/query_editor/_query_editor.scss index 7edfebfed938..770160de8c1d 100644 --- a/src/plugins/data/public/ui/query_editor/_query_editor.scss +++ b/src/plugins/data/public/ui/query_editor/_query_editor.scss @@ -193,6 +193,7 @@ .osdQuerEditor__singleLine { padding: $euiSizeS; background-color: $euiColorEmptyShade; + overflow: initial !important; // needed for suggestion window, otherwise will be hidden in child .monaco-editor .view-overlays .current-line { border: none; diff --git a/src/plugins/data/public/ui/query_editor/query_editor.tsx b/src/plugins/data/public/ui/query_editor/query_editor.tsx index 2ff643f74254..dd0fec884f6a 100644 --- a/src/plugins/data/public/ui/query_editor/query_editor.tsx +++ b/src/plugins/data/public/ui/query_editor/query_editor.tsx @@ -18,9 +18,15 @@ import classNames from 'classnames'; import { isEqual } from 'lodash'; import React, { Component, createRef, RefObject } from 'react'; import { monaco } from '@osd/monaco'; -import { IDataPluginServices, IFieldType, IIndexPattern, Query, TimeRange } from '../..'; +import { + IDataPluginServices, + IFieldType, + IIndexPattern, + Query, + QuerySuggestion, + TimeRange, +} from '../..'; import { OpenSearchDashboardsReactContextValue } from '../../../../opensearch_dashboards_react/public'; -import { QuerySuggestion } from '../../autocomplete'; import { fromUser, getQueryLog, PersistedLog, toUser } from '../../query'; import { SuggestionsListSize } from '../typeahead/suggestions_component'; import { QueryLanguageSelector } from './language_selector'; @@ -30,12 +36,7 @@ import { DatasetSelector } from '../dataset_selector'; import { QueryControls } from '../../query/query_string/language_service/get_query_control_links'; import { RecentQueriesTable } from '../../query/query_string/language_service/recent_query'; import { DefaultInputProps } from './editors'; - -const LANGUAGE_ID_SQL = 'SQL'; -monaco.languages.register({ id: LANGUAGE_ID_SQL }); - -const LANGUAGE_ID_KUERY = 'kuery'; -monaco.languages.register({ id: LANGUAGE_ID_KUERY }); +import { MonacoCompatibleQuerySuggestion } from '../../autocomplete/providers/query_suggestion_provider'; export interface QueryEditorProps { query: Query; @@ -285,7 +286,7 @@ export default class QueryEditorUI extends Component { // current completion item range being given as last 'word' at pos const wordUntil = model.getWordUntilPosition(position); - const range = new monaco.Range( + const defaultRange = new monaco.Range( position.lineNumber, wordUntil.startColumn, position.lineNumber, @@ -295,12 +296,17 @@ export default class QueryEditorUI extends Component { return { suggestions: suggestions && suggestions.length > 0 - ? suggestions.map((s: QuerySuggestion) => ({ - label: s.text, - kind: s.type as monaco.languages.CompletionItemKind, - insertText: s.insertText ?? s.text, - range, - })) + ? suggestions + .filter((s) => 'detail' in s) // remove suggestion not of type MonacoCompatible + .map((s: MonacoCompatibleQuerySuggestion) => { + return { + label: s.text, + kind: s.type as monaco.languages.CompletionItemKind, + insertText: s.insertText ?? s.text, + range: s.replacePosition ?? defaultRange, + detail: s.detail, + }; + }) : [], incomplete: false, }; From 2b33f344e269d0e2c31c0b1dc48d1476f9599939 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:08:53 -0700 Subject: [PATCH 273/276] fix(discover): add data source management link in data selector (#7929) (#7949) (cherry picked from commit b66f16babff0a7e4bb2a5566a621b6cf2ed40363) Signed-off-by: Joshua Li Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] --- .../public/ui/dataset_selector/dataset_explorer.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx b/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx index b634f21dfe00..ab967bf413ba 100644 --- a/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx +++ b/src/plugins/data/public/ui/dataset_selector/dataset_explorer.tsx @@ -79,8 +79,14 @@ export const DatasetExplorer = ({ id="data.explorer.datasetSelector.advancedSelector.description" defaultMessage="Select from those available to you. " /> - - Manage data sources + +

From 39bef8cea8b7086092eefd7ae82c22c2fc59da22 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 09:37:09 +0800 Subject: [PATCH 274/276] [Workspace] Update collaborator input to text field (#7879) (#7941) * Change the collaborator input from a combobox to a text field * resolve some problems * Changeset file for PR #7879 created/updated * resolve some issues --------- (cherry picked from commit 4c1e3e60f97bbb9d11c0f925ec5e44d64ab3565b) Signed-off-by: Kapian1234 Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7879.yml | 2 ++ ...orkspace_permission_setting_input.test.tsx | 24 ++++--------- .../workspace_permission_setting_input.tsx | 35 ++++++------------- ...orkspace_permission_setting_panel.test.tsx | 17 ++++----- 4 files changed, 25 insertions(+), 53 deletions(-) create mode 100644 changelogs/fragments/7879.yml diff --git a/changelogs/fragments/7879.yml b/changelogs/fragments/7879.yml new file mode 100644 index 000000000000..68a7f88ad045 --- /dev/null +++ b/changelogs/fragments/7879.yml @@ -0,0 +1,2 @@ +feat: +- Update the collaborator input from a combobox to a text field ([#7879](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7879)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx index d524eb05887e..72d0415f5984 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.test.tsx @@ -75,7 +75,7 @@ describe('WorkspacePermissionSettingInput', () => { modes: [WorkspacePermissionMode.LibraryRead, WorkspacePermissionMode.Read], }); - expect(renderResult.getByText('foo')).toBeInTheDocument(); + expect(renderResult.getByDisplayValue('foo')).toBeInTheDocument(); expect(renderResult.getByText('Read')).toBeInTheDocument(); }); it('should render consistent group id and permission modes', () => { @@ -85,18 +85,17 @@ describe('WorkspacePermissionSettingInput', () => { modes: [WorkspacePermissionMode.LibraryWrite, WorkspacePermissionMode.Read], }); - expect(renderResult.getByText('bar')).toBeInTheDocument(); + expect(renderResult.getByDisplayValue('bar')).toBeInTheDocument(); expect(renderResult.getByText('Read & Write')).toBeInTheDocument(); }); it('should call onGroupOrUserIdChange with user id', () => { const { renderResult, onGroupOrUserIdChangeMock } = setup(); expect(onGroupOrUserIdChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getByText('Select a user')); - fireEvent.input(renderResult.getAllByTestId('comboBoxSearchInput')[0], { + fireEvent.change(renderResult.getAllByTestId('workspaceFormUserIdOrGroupInput')[0], { target: { value: 'user1' }, }); - fireEvent.blur(renderResult.getAllByTestId('comboBoxSearchInput')[0]); + fireEvent.blur(renderResult.getAllByTestId('workspaceFormUserIdOrGroupInput')[0]); expect(onGroupOrUserIdChangeMock).toHaveBeenCalledWith({ type: 'user', userId: 'user1' }, 0); }); it('should call onGroupOrUserIdChange with group', () => { @@ -105,24 +104,13 @@ describe('WorkspacePermissionSettingInput', () => { }); expect(onGroupOrUserIdChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getByText('Select a user group')); - fireEvent.input(renderResult.getAllByTestId('comboBoxSearchInput')[0], { + fireEvent.change(renderResult.getAllByTestId('workspaceFormUserIdOrGroupInput')[0], { target: { value: 'group' }, }); - fireEvent.blur(renderResult.getAllByTestId('comboBoxSearchInput')[0]); + fireEvent.blur(renderResult.getAllByTestId('workspaceFormUserIdOrGroupInput')[0]); expect(onGroupOrUserIdChangeMock).toHaveBeenCalledWith({ type: 'group', group: 'group' }, 0); }); - it('should call onGroupOrUserIdChange without user id after clear button clicked', () => { - const { renderResult, onGroupOrUserIdChangeMock } = setup({ - userId: 'foo', - }); - - expect(onGroupOrUserIdChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getByTestId('comboBoxClearButton')); - expect(onGroupOrUserIdChangeMock).toHaveBeenCalledWith({ type: 'user' }, 0); - }); - it('should call onPermissionModesChange with permission modes after permission modes changed', () => { const { renderResult, onPermissionModesChangeMock } = setup({}); diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx index 87d5ccb3a418..00560f7c033d 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_input.tsx @@ -7,11 +7,10 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, - EuiComboBox, EuiButtonIcon, - EuiComboBoxOptionOption, EuiSuperSelect, EuiSuperSelectOption, + EuiFieldText, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; import { WorkspacePermissionMode } from '../../../common/constants'; @@ -104,19 +103,15 @@ export const WorkspacePermissionSettingInput = ({ onPermissionModesChange, onTypeChange, }: WorkspacePermissionSettingInputProps) => { - const groupOrUserIdSelectedOptions = useMemo( - () => (group || userId ? [{ label: (group || userId) as string }] : []), - [group, userId] - ); - const permissionModesSelected = useMemo( () => getPermissionModeId(modes ?? []), [modes] ); - const handleGroupOrUserIdCreate = useCallback( - (groupOrUserId) => { + const handleGroupOrUserIdChange = useCallback( + (event) => { + const groupOrUserId = event.target.value; onGroupOrUserIdChange( type === WorkspacePermissionItemType.Group ? { type, group: groupOrUserId } @@ -127,15 +122,6 @@ export const WorkspacePermissionSettingInput = ({ [index, type, onGroupOrUserIdChange] ); - const handleGroupOrUserIdChange = useCallback( - (options: Array>) => { - if (options.length === 0) { - onGroupOrUserIdChange({ type }, index); - } - }, - [index, type, onGroupOrUserIdChange] - ); - const handlePermissionModeOptionChange = useCallback( (id: string) => { if (optionIdToWorkspacePermissionModesMap[id]) { @@ -165,22 +151,21 @@ export const WorkspacePermissionSettingInput = ({ /> - diff --git a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx index a6249584bcea..2bf0903361c0 100644 --- a/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx +++ b/src/plugins/workspace/public/components/workspace_form/workspace_permission_setting_panel.test.tsx @@ -76,10 +76,10 @@ describe('WorkspacePermissionSettingInput', () => { it('should render consistent user and group permissions', () => { const { renderResult } = setup(); - expect(renderResult.getByText('foo')).toBeInTheDocument(); + expect(renderResult.getByDisplayValue('foo')).toBeInTheDocument(); expect(renderResult.getByText('Read')).toBeInTheDocument(); - expect(renderResult.getByText('bar')).toBeInTheDocument(); + expect(renderResult.getByDisplayValue('bar')).toBeInTheDocument(); expect(renderResult.getByText('Read & Write')).toBeInTheDocument(); }); @@ -202,11 +202,12 @@ describe('WorkspacePermissionSettingInput', () => { ]); }); - it('should call onGroupOrUserIdChange without user id after clear button clicked', () => { + it('should call onGroupOrUserIdChange after user value changed', () => { const { renderResult, onChangeMock } = setup(); expect(onChangeMock).not.toHaveBeenCalled(); - fireEvent.click(renderResult.getAllByTestId('comboBoxClearButton')[0]); + const inputElement = renderResult.getByDisplayValue('foo'); + fireEvent.change(inputElement, { target: { value: 'fooo' } }); expect(onChangeMock).toHaveBeenCalled(); }); @@ -229,12 +230,8 @@ describe('WorkspacePermissionSettingInput', () => { disabledUserOrGroupInputIds: [0, 1], }); - expect(renderResult.getByText('user-1')?.closest('div[role="combobox"]')).toHaveClass( - 'euiComboBox-isDisabled' - ); - expect(renderResult.getByText('user-group-1')?.closest('div[role="combobox"]')).toHaveClass( - 'euiComboBox-isDisabled' - ); + expect(renderResult.getByDisplayValue('user-1')).toBeDisabled(); + expect(renderResult.getByDisplayValue('user-group-1')).toBeDisabled(); }); it('should render consistent errors', () => { From 7e003d866a6eda628e8dc102c4a4e194930bb558 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:12:33 +0800 Subject: [PATCH 275/276] [Workspace] refactor: workspace initial page (#7857) (#7942) * refactor: workspace initial page * Changeset file for PR #7857 created/updated * update the describe content * update the url and title --------- (cherry picked from commit 6c7a5bb0dc59c9bf5c845f2f17004c1f1195ef34) Signed-off-by: yubonluo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7857.yml | 2 + .../workspace_initial.test.tsx.snap | 681 +++++++++--------- .../workspace_initial/workspace_initial.tsx | 164 ++--- 3 files changed, 405 insertions(+), 442 deletions(-) create mode 100644 changelogs/fragments/7857.yml diff --git a/changelogs/fragments/7857.yml b/changelogs/fragments/7857.yml new file mode 100644 index 000000000000..2e462a9cdac0 --- /dev/null +++ b/changelogs/fragments/7857.yml @@ -0,0 +1,2 @@ +refactor: +- [Workspace] workspace initial page ([#7857](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7857)) \ No newline at end of file diff --git a/src/plugins/workspace/public/components/workspace_initial/__snapshots__/workspace_initial.test.tsx.snap b/src/plugins/workspace/public/components/workspace_initial/__snapshots__/workspace_initial.test.tsx.snap index 67dc620d5834..5f294beb33a9 100644 --- a/src/plugins/workspace/public/components/workspace_initial/__snapshots__/workspace_initial.test.tsx.snap +++ b/src/plugins/workspace/public/components/workspace_initial/__snapshots__/workspace_initial.test.tsx.snap @@ -30,7 +30,7 @@ exports[`WorkspaceInitial render workspace initial page normally when theme is d />
- Getting started with OpenSearch + Create a workspace to get started
- OpenSearch is a flexible, scalable, open-source way to build solutions for data-intensive search and analytics applications. Explore, enrich, and visualize your data, using developer-friendly tools and powerful integrations for machine learning, data processing, and more. + Welcome to OpenSearch! This interface supports you to easily explore, enrich and visualize your data with developer-friendly tools and powerful integrations for machine learning, data process, and more. To begin, create a workspace for your use case.
- Learn more from documentation and more. + Learn more from documentation
@@ -90,42 +90,40 @@ exports[`WorkspaceInitial render workspace initial page normally when theme is d
+
+ +
@@ -133,54 +131,35 @@ exports[`WorkspaceInitial render workspace initial page normally when theme is d class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Create a workspace + Observability

- - Organize projects by use case in a collaborative workspace. - + Gain visibility into your applications and infrastructure

-
+
+ +
@@ -188,40 +167,35 @@ exports[`WorkspaceInitial render workspace initial page normally when theme is d class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Try OpenSearch + Security Analytics

- Explore sample data before adding your own. + Enhance your security posture with advanced analytics

-
+
+ +
@@ -229,40 +203,35 @@ exports[`WorkspaceInitial render workspace initial page normally when theme is d class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Add your data + Search

- Start collecting and analyzing your data. + Discover and query your data with ease

-
+
+ +
@@ -270,55 +239,73 @@ exports[`WorkspaceInitial render workspace initial page normally when theme is d class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Discover insights + Essentials

- Explore data interactively to uncover insights. + Just the basics for exploring and analyzing data

- +
+
+
+
+
+
-
+ Create Workspace + + +
-
-

- And much more... -

-
+   Explore live demo environment at + + + playground.opensearch.org +
@@ -343,7 +330,7 @@ exports[`WorkspaceInitial render workspace initial page normally when theme is d class="euiButtonEmpty__text" >
Settings and setup
@@ -387,7 +374,7 @@ exports[`WorkspaceInitial render workspace initial page normally when user is da />
- Getting started with OpenSearch + Create a workspace to get started
- OpenSearch is a flexible, scalable, open-source way to build solutions for data-intensive search and analytics applications. Explore, enrich, and visualize your data, using developer-friendly tools and powerful integrations for machine learning, data processing, and more. + Welcome to OpenSearch! This interface supports you to easily explore, enrich and visualize your data with developer-friendly tools and powerful integrations for machine learning, data process, and more. To begin, create a workspace for your use case.
- Learn more from documentation and more. + Learn more from documentation
@@ -447,42 +434,40 @@ exports[`WorkspaceInitial render workspace initial page normally when user is da
+

+ Create a workspace +

-
- -   Explore live demo environment at - - - playground.opensearch.org - -
+ Organize projects by use case in a collaborative workspace
+
+ +
@@ -490,54 +475,35 @@ exports[`WorkspaceInitial render workspace initial page normally when user is da class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Create a workspace + Observability

- - Organize projects by use case in a collaborative workspace. - + Gain visibility into your applications and infrastructure

-
+
+ +
@@ -545,40 +511,35 @@ exports[`WorkspaceInitial render workspace initial page normally when user is da class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Try OpenSearch + Security Analytics

- Explore sample data before adding your own. + Enhance your security posture with advanced analytics

-
+
+ +
@@ -586,40 +547,35 @@ exports[`WorkspaceInitial render workspace initial page normally when user is da class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Add your data + Search

- Start collecting and analyzing your data. + Discover and query your data with ease

-
+
+ +
@@ -627,55 +583,73 @@ exports[`WorkspaceInitial render workspace initial page normally when user is da class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Discover insights + Essentials

- Explore data interactively to uncover insights. + Just the basics for exploring and analyzing data

- +
+
+
+
+
+
-
+ Create Workspace + + +
-
-

- And much more... -

-
+   Explore live demo environment at + + + playground.opensearch.org +
@@ -700,7 +674,7 @@ exports[`WorkspaceInitial render workspace initial page normally when user is da class="euiButtonEmpty__text" >
Settings and setup
@@ -744,7 +718,7 @@ exports[`WorkspaceInitial render workspace initial page normally when user is no />
- Getting started with OpenSearch + Create a workspace to get started
- OpenSearch is a flexible, scalable, open-source way to build solutions for data-intensive search and analytics applications. Explore, enrich, and visualize your data, using developer-friendly tools and powerful integrations for machine learning, data processing, and more. + Welcome to OpenSearch! This interface supports you to easily explore, enrich and visualize your data with developer-friendly tools and powerful integrations for machine learning, data process, and more. To begin, create a workspace for your use case.
- Learn more from documentation and more. + Learn more from documentation
@@ -804,42 +778,40 @@ exports[`WorkspaceInitial render workspace initial page normally when user is no
+

+ Create a workspace +

-
- -   Explore live demo environment at - - - playground.opensearch.org - -
+ Organize projects by use case in a collaborative workspace
+
+ +
@@ -847,18 +819,14 @@ exports[`WorkspaceInitial render workspace initial page normally when user is no class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Create a workspace + Observability

- - Organize projects by use case in a collaborative workspace. - + Gain visibility into your applications and infrastructure

@@ -868,9 +836,18 @@ exports[`WorkspaceInitial render workspace initial page normally when user is no class="euiFlexItem euiFlexItem--flexGrowZero" >
+
+ +
@@ -878,40 +855,35 @@ exports[`WorkspaceInitial render workspace initial page normally when user is no class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Try OpenSearch + Security Analytics

- Explore sample data before adding your own. + Enhance your security posture with advanced analytics

-
+
+ +
@@ -919,40 +891,35 @@ exports[`WorkspaceInitial render workspace initial page normally when user is no class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Add your data + Search

- Start collecting and analyzing your data. + Discover and query your data with ease

-
+
+ +
@@ -960,55 +927,59 @@ exports[`WorkspaceInitial render workspace initial page normally when user is no class="euiTitle euiTitle--small euiCard__title" id="generated-idTitle" > - Discover insights + Essentials

- Explore data interactively to uncover insights. + Just the basics for exploring and analyzing data

-
+
+
+
+
+ Contact your administrator to create a workspace or to be added to an existing one. +
+
+
+
-
-

- And much more... -

-
+   Explore live demo environment at + + + playground.opensearch.org +
@@ -1033,7 +1004,7 @@ exports[`WorkspaceInitial render workspace initial page normally when user is no class="euiButtonEmpty__text" >
Settings and setup
diff --git a/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx b/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx index 85b158a0928a..7e77a2fa1130 100644 --- a/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx +++ b/src/plugins/workspace/public/components/workspace_initial/workspace_initial.tsx @@ -20,7 +20,6 @@ import { EuiFlexGroup, EuiPageContent, EuiSmallButton, - EuiToolTip, EuiSmallButtonEmpty, } from '@elastic/eui'; import { i18n } from '@osd/i18n'; @@ -40,11 +39,6 @@ export const WorkspaceInitial = () => { const isDarkTheme = uiSettings.get('theme:darkMode'); const backGroundUrl = isDarkTheme ? BackgroundDarkSVG : BackgroundLightSVG; - const noAdminToolTip = i18n.translate('workspace.initial.card.createWorkspace.toolTip', { - defaultMessage: - 'Contact your administrator to create a workspace or to be added to an existing one.', - }); - const createButton = ( { ); + const noAdminText = ( + + {i18n.translate('workspace.initial.card.createWorkspace.text', { + defaultMessage: + 'Contact your administrator to create a workspace or to be added to an existing one.', + })} + + ); + const cards = ( - - - - <> - {i18n.translate('workspace.initial.card.createWorkspace.description', { - defaultMessage: 'Organize projects by use case in a collaborative workspace.', - })} - - - } - footer={isDashboardAdmin && createButton} - /> - + } + title={i18n.translate('workspace.initial.card.observability.title', { + defaultMessage: 'Observability', })} - description={i18n.translate('workspace.initial.card.tryOpenSearch.description', { - defaultMessage: 'Explore sample data before adding your own.', + description={i18n.translate('workspace.initial.card.observability.description', { + defaultMessage: 'Gain visibility into your applications and infrastructure', })} - footer={ - - {i18n.translate('workspace.initial.card.tryOpenSearch.footer', { - defaultMessage: 'with Sample Datasets', - })} - - } /> } + title={i18n.translate('workspace.initial.card.securityAnalytics.title', { + defaultMessage: 'Security Analytics', })} - description={i18n.translate('workspace.initial.card.addData.description', { - defaultMessage: 'Start collecting and analyzing your data.', + description={i18n.translate('workspace.initial.card.securityAnalytics.description', { + defaultMessage: 'Enhance your security posture with advanced analytics', })} - footer={ - - {i18n.translate('workspace.initial.card.addData.footer', { - defaultMessage: 'with Getting Started Guide', - })} - - } /> } + title={i18n.translate('workspace.initial.card.search.title', { + defaultMessage: 'Search', })} - description={i18n.translate('workspace.initial.card.discoverInsights.description', { - defaultMessage: 'Explore data interactively to uncover insights.', + description={i18n.translate('workspace.initial.card.search.description', { + defaultMessage: 'Discover and query your data with ease', })} - footer={ - - {i18n.translate('workspace.initial.card.discoverInsights.footer', { - defaultMessage: 'with Discover', - })} - - } /> } + title={i18n.translate('workspace.initial.card.essentials.title', { + defaultMessage: 'Essentials', + })} + description={i18n.translate('workspace.initial.card.essentials.description', { + defaultMessage: 'Just the basics for exploring and analyzing data', })} /> @@ -155,45 +125,65 @@ export const WorkspaceInitial = () => {

{i18n.translate('workspace.initial.title', { - defaultMessage: 'Getting started with OpenSearch', + defaultMessage: 'Create a workspace to get started', })}

- - + + {i18n.translate('workspace.initial.description', { defaultMessage: - 'OpenSearch is a flexible, scalable, open-source way to build solutions for data-intensive search and analytics applications. Explore, enrich, and visualize your data, using developer-friendly tools and powerful integrations for machine learning, data processing, and more.', + 'Welcome to OpenSearch! This interface supports you to easily explore, enrich and visualize your data with developer-friendly tools and powerful integrations for machine learning, data process, and more. To begin, create a workspace for your use case.', })} - + {i18n.translate('workspace.initial.button.openSearch', { - defaultMessage: 'Learn more from documentation and more.', + defaultMessage: 'Learn more from documentation', })} - - - - - -   Explore live demo environment at{' '} - playground.opensearch.org - - + + +

+ {i18n.translate('workspace.initial.createWorkspace.title', { + defaultMessage: 'Create a workspace', + })} +

+
+ + {i18n.translate('workspace.initial.createWorkspace.describe', { + defaultMessage: 'Organize projects by use case in a collaborative workspace', + })} +
{cards} + + + {isDashboardAdmin ? createButton : noAdminText} + + + + +   Explore live demo environment at{' '} + + playground.opensearch.org + + + + + +
); @@ -205,7 +195,7 @@ export const WorkspaceInitial = () => { - + { href={settingsAndSetupUrl} data-test-subj="workspace-initial-button-settingsAndSetup" > - + {i18n.translate('workspace.initial.button.settingsAndSetup', { defaultMessage: 'Settings and setup', })} From cf6255c1218ab6a039388a5cfff3cae239fc2f74 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:25:07 +0800 Subject: [PATCH 276/276] [Bug][Workspace]fix: revert new home page ui setting for workspace default route (#7858) (#7914) * revert new home page ui setting for workspace default route * Changeset file for PR #7858 created/updated --------- (cherry picked from commit a0365d86030caffc486d2dae8a5621640a95f997) Signed-off-by: yubonluo Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/7858.yml | 2 + src/plugins/workspace/server/plugin.test.ts | 42 --------------------- src/plugins/workspace/server/plugin.ts | 13 ++----- 3 files changed, 6 insertions(+), 51 deletions(-) create mode 100644 changelogs/fragments/7858.yml diff --git a/changelogs/fragments/7858.yml b/changelogs/fragments/7858.yml new file mode 100644 index 000000000000..6145c80780a7 --- /dev/null +++ b/changelogs/fragments/7858.yml @@ -0,0 +1,2 @@ +fix: +- [Workspace] Revert new home page ui setting for workspace default route ([#7858](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/7858)) \ No newline at end of file diff --git a/src/plugins/workspace/server/plugin.test.ts b/src/plugins/workspace/server/plugin.test.ts index b71532e36273..433fb2703f00 100644 --- a/src/plugins/workspace/server/plugin.test.ts +++ b/src/plugins/workspace/server/plugin.test.ts @@ -183,23 +183,6 @@ describe('Workspace server plugin', () => { describe('#setUpRedirectPage', () => { const setupMock = coreMock.createSetup(); const uiSettingsMock = uiSettingsServiceMock.createClient(); - setupMock.getStartServices.mockResolvedValue([ - { - ...coreMock.createStart(), - uiSettings: { - asScopedToClient: () => ({ - ...uiSettingsMock, - get: jest.fn().mockImplementation((key) => { - if (key === 'home:useNewHomePage') { - return Promise.resolve(true); - } - }), - }), - }, - }, - {}, - {}, - ]); const initializerContextConfigMock = coreMock.createPluginInitializerContext({ enabled: true, permission: { @@ -304,8 +287,6 @@ describe('Workspace server plugin', () => { get: jest.fn().mockImplementation((key) => { if (key === 'defaultWorkspace') { return Promise.resolve('defaultWorkspace'); - } else if (key === 'home:useNewHomePage') { - return Promise.resolve('true'); } }), }), @@ -337,29 +318,6 @@ describe('Workspace server plugin', () => { }, }); }); - - it('with / request path and home:useNewHomePage is false', async () => { - const request = httpServerMock.createOpenSearchDashboardsRequest({ - path: '/', - }); - setupMock.getStartServices.mockResolvedValue([ - { - ...coreMock.createStart(), - uiSettings: { - asScopedToClient: () => ({ - ...uiSettingsMock, - get: jest.fn().mockResolvedValue(false), - }), - }, - }, - {}, - {}, - ]); - const toolKitMock = httpServerMock.createToolkit(); - - await registerOnPostAuthFn(request, response, toolKitMock); - expect(toolKitMock.next).toBeCalledTimes(1); - }); }); it('#start', async () => { diff --git a/src/plugins/workspace/server/plugin.ts b/src/plugins/workspace/server/plugin.ts index d7c1ba69206c..21f90fbe0d91 100644 --- a/src/plugins/workspace/server/plugin.ts +++ b/src/plugins/workspace/server/plugin.ts @@ -114,15 +114,6 @@ export class WorkspacePlugin implements Plugin { const path = request.url.pathname; if (path === '/') { - const [coreStart] = await core.getStartServices(); - const uiSettings = coreStart.uiSettings.asScopedToClient( - coreStart.savedObjects.getScopedClient(request) - ); - const useNewHomePage = await uiSettings.get('home:useNewHomePage'); - if (!useNewHomePage) { - return toolkit.next(); - } - const workspaceListResponse = await this.client?.list( { request, logger: this.logger }, { page: 1, perPage: 100 } @@ -139,6 +130,10 @@ export class WorkspacePlugin implements Plugin